├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── NOTICES.txt ├── README.md ├── RELEASE_NOTES.md ├── _clang-format ├── build ├── prebuild_linux.sh └── prebuild_windows.bat ├── documentation ├── cli_documentation.md ├── isa_decoder │ ├── api_documentation.md │ └── api_tutorial.md ├── isa_explorer │ ├── api_documentation.md │ └── api_tutorial.md ├── spec_documentation.md └── unit_tests_documentation.md ├── include └── amdisa │ ├── api_version.h │ ├── isa_decoder.h │ └── isa_explorer.h ├── source ├── common │ ├── amdisa_expression_tree_consts.h │ ├── amdisa_structures.cpp │ ├── amdisa_structures.h │ ├── amdisa_utility.cpp │ ├── amdisa_utility.h │ ├── amdisa_xml_element_consts.h │ ├── isa_xml_reader.cpp │ ├── isa_xml_reader.h │ ├── logger.cpp │ └── logger.h ├── examples │ ├── CMakeLists.txt │ ├── basic_decoder.cpp │ ├── basic_explorer.cpp │ └── multi_arch_decoder.cpp ├── isa_decoder │ ├── CMakeLists.txt │ ├── encoding_condition_handler.hpp │ └── isa_decoder.cpp ├── isa_explorer │ ├── CMakeLists.txt │ └── isa_explorer.cpp ├── isa_spec_cli │ ├── CMakeLists.txt │ ├── cli_processor │ │ ├── cli_command.h │ │ ├── cli_command_decode_machine_code.cpp │ │ ├── cli_command_decode_machine_code.h │ │ ├── cli_command_decode_shader_file.cpp │ │ ├── cli_command_decode_shader_file.h │ │ ├── cli_command_generate_inst_desc.cpp │ │ ├── cli_command_generate_inst_desc.h │ │ ├── cli_command_get_inst_info.cpp │ │ ├── cli_command_get_inst_info.h │ │ ├── cli_command_print_help.cpp │ │ ├── cli_command_print_help.h │ │ ├── cli_command_read_xml.cpp │ │ ├── cli_command_read_xml.h │ │ ├── cli_processor.h │ │ ├── public_cli_processor.cpp │ │ └── public_cli_processor.h │ └── main.cpp └── third_party │ ├── cxxopts │ └── cxxopts.hpp │ ├── json │ └── json.hpp │ └── tinyxml2 │ ├── tinyxml2.cpp │ └── tinyxml2.h └── test ├── run_unit_tests.py ├── source ├── CMakeLists.txt ├── include │ └── amdisa_tests.h ├── main.cpp ├── test_decode_inst.cpp ├── test_decode_text.cpp └── test_initialize.cpp └── third_party └── catch2 └── catch.hpp /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Compiled Object files 5 | *.slo 6 | *.lo 7 | *.o 8 | *.obj 9 | 10 | # Precompiled Headers 11 | *.gch 12 | *.pch 13 | 14 | # Compiled Dynamic libraries 15 | *.so 16 | *.dylib 17 | *.dll 18 | 19 | # Fortran module files 20 | *.mod 21 | *.smod 22 | 23 | # Compiled Static libraries 24 | *.lai 25 | *.la 26 | *.a 27 | *.lib 28 | 29 | # Executables 30 | *.exe 31 | *.out 32 | *.app 33 | 34 | # Visual Studio project files 35 | *.sln 36 | *.vcxproj* 37 | .vs 38 | projects 39 | x64 40 | 41 | # cmake files 42 | CMakeFiles 43 | CMakeCache.txt 44 | cmake_install.cmake 45 | 46 | # Directories 47 | build/linux/ 48 | build/windows/ 49 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2021-2024 Advanced Micro Devices, Inc. All rights reserved. 2 | cmake_minimum_required(VERSION 3.0) 3 | 4 | # List of projects. 5 | project(isa_spec_manager) 6 | 7 | # Setting compiler flags. 8 | if (LINUX) 9 | set(CMAKE_CXX_COMPILER g++) 10 | endif () 11 | set(CMAKE_CXX_STANDARD 14) 12 | set(CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS} ${FLAGS}) 13 | 14 | # Enable using folders to group projects on Windows (Visual Studio solution). 15 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 16 | 17 | # Windows solution generator is a multi config generator, so define 18 | # CMAKE_CONFIGURATION_TYPES, which enables usage of $<$value2> syntax for Windows settings. 19 | if (${CMAKE_SYSTEM_NAME} STREQUAL "Windows") 20 | # Visual Studio 21 | set(CMAKE_CONFIGURATION_TYPES "Release;Debug") 22 | endif () 23 | 24 | # Setting project directories. 25 | # XML ISA Spec Decoder API: accepts ISA Spec for specific architecture 26 | # and provides interface for decoding of instructions or data retrieval 27 | # for specific instructions in the architecture. 28 | add_subdirectory(./source/isa_decoder) 29 | 30 | if (EXCLUDE_ISA_CLI_EXAMPLES_TESTS) 31 | message("-- Excluding CLI, examples and tests.") 32 | else() 33 | # Examples: demonstrates utilities and API features using example apps 34 | add_subdirectory(./source/examples) 35 | 36 | # CLI commands: provides command line interface implementation 37 | # for generation of various CLI programs. 38 | add_subdirectory(./source/isa_spec_cli) 39 | 40 | # ISA explorer API 41 | add_subdirectory(./source/isa_explorer) 42 | 43 | # Unit testing suite 44 | add_subdirectory(./test/source) 45 | endif () 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 GPUOpen-Tools 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /NOTICES.txt: -------------------------------------------------------------------------------- 1 | Third-party licenses, acknowledgements 2 | ====================================== 3 | 4 | isa_spec_manager uses the following third-party software: 5 | 6 | **cxxopts** 7 | 8 | Copyright (c) 2014 Jarryd Beck 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in 18 | all copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 26 | THE SOFTWARE. 27 | 28 | **nlohmann/json** 29 | 30 | Copyright © 2013-2018 Niels Lohmann 31 | 32 | **TinyXML-2** 33 | 34 | TinyXML-2 is released under the zlib license: 35 | 36 | This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. 37 | 38 | Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 39 | 40 | The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 41 | Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 42 | This notice may not be removed or altered from any source distribution. 43 | 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # isa_spec_manager 2 | A set of tools for parsing and using AMD's machine-readable GPU ISA specifications. 3 | 4 | The `IsaDecoder` API makes it easy to parse the specification XML files, decode instructions and even decode whole shaders. 5 | 6 | The `explorer::Spec` experimental API lets you iterate over the elements of a given specification file. 7 | 8 | For usage examples, see the [examples subfolder](https://github.com/GPUOpen-Tools/isa_spec_manager/tree/main/source/examples). 9 | 10 | ## Building isa_spec_manager 11 | To build the project, use the build scripts located in the ./build subfolder. Please note that the build process requires CMake with minimum version of 3.0. 12 | 13 | ### Building on Linux 14 | ``` 15 | cd ./isa_spec_manager/build 16 | ./prebuild_linux.sh 17 | cd linux 18 | make 19 | ``` 20 | 21 | The above script will launch the cmake. The script will generate projects directory. 22 | 23 | ### Building on Windows 24 | ``` 25 | cd ./isa_spec_manager/build 26 | ./prebuild_windows.bat 27 | ``` 28 | 29 | The above script will create a `windows` subfolder and generate a Visual Studio solution within it. 30 | 31 | By default, a solution is generated for VS 2022. To generate a solution for a different VS version or to use a different MSVC toolchain use the `--vs` argument. 32 | For example, to generate the solution for VS 2019 with the VS 2019 toolchain, run: 33 | 34 | `` 35 | ./prebuild_windows.bat --vs 2019 36 | `` 37 | 38 | ## Using the API 39 | For the API and specification documentation, please see the [documentation subfolder](https://github.com/GPUOpen-Tools/isa_spec_manager/tree/main/documentation). 40 | 41 | The following example files can give you a quick overview of how to start using the XML ISA spec in your project: 42 | 43 | ### IsaDecoder 44 | * Basic usage example: [./source/examples/basic_decoder.cpp](./source/examples/basic_decoder.cpp). This sample requires a single command line argument which is a full path to the XML specification file. 45 | * Usage example with multiple architectures in flight: [./source/examples/multi_arch_decoder.cpp](./source/examples/multi_arch_decoder.cpp). This sample requires one or more command line arguments which are the full paths to the XML specification files. 46 | 47 | ### explorer::Spec 48 | * Basic usage example: [./source/examples/basic_explorer.cpp](./source/examples/basic_explorer.cpp). This sample requires a single command line argument which is a full path to the XML specification file. 49 | 50 | 51 | ## Getting the ISA specification files 52 | The Machine-Readable GPU ISA specification files can be downloaded from [AMD's Machine-Readable GPU ISA Specification page on GPUOpen.com](https://gpuopen.com/machine-readable-isa). 53 | -------------------------------------------------------------------------------- /RELEASE_NOTES.md: -------------------------------------------------------------------------------- 1 | # AMD's Machine-Readable ISA Specification and Tools - Release Notes # 2 | 3 | ## Highlights of this release ## 4 | 5 | AMD's machine-readable GPU Instruction Set Architecture specifications is a set of XML files that describe AMD's latest GPU ISA: instructions, encodings, operands, data formats and even human-readable description strings. 6 | 7 | The first release includes the specification XML files for the following GPU architectures: 8 | * AMD CDNA™ 3 (Instinct™ MI300) 9 | * AMD CDNA™ 2 (Instinct™ MI200) 10 | * AMD CDNA™ 1 (Instinct™ MI100) 11 | * AMD RDNA™ 3 12 | * AMD RDNA™ 2 13 | * AMD RDNA™ 1 14 | 15 | The XML files can be downloaded from [GPUOpen.com](https://gpuopen.com/machine-readable-isa/). 16 | 17 | This codebase includes the `IsaDecoder` API that can be used to decode, which can be used to decode AMD ISA assembly and disassembly using the specifications: 18 | * Load XML specification files and automatically parse them, so you don't need to write your own parser. 19 | * Decode single instructions and whole kernels and shaders in binary or text format. 20 | * Handle multiple architectures in flight with the `DecodeManager` convenience API. 21 | 22 | For usage examples and instructions on how to build the project, please see [source/examples subdirectory on the isa_spec_manager GitHub repository](https://github.com/GPUOpen-Tools/isa_spec_manager). 23 | 24 | **Note:** while the `IsaDecoder` API is a good way to get started with parsing the XML files, nothing prevents you from parsing the files yourself and building your own custom workflow. To do that please refer to the XML schema documentation [XML schema documentation](https://github.com/GPUOpen-Tools/isa_spec_manager/blob/main/documentation/spec_documentation.md). 25 | 26 | New in this release: 27 | * Added support for operand subtypes (requires XML schema version `v1.1.0`). 28 | * Introducing the experimental `explorer::Spec` API for iterating over the elements of a given specification file. See the [documentation](https://github.com/GPUOpen-Tools/isa_spec_manager/tree/main/documentation) and [examples](https://github.com/GPUOpen-Tools/isa_spec_manager/tree/main/source/examples) subfolders for more details. 29 | * On Windows, the solution is now generated for the VS2022 toolchain by default. 30 | * Unit tests are now part of the repository. 31 | * Bug fixes and performance improvements. 32 | 33 | ## Known issues ## 34 | 35 | ### Specification ### 36 | * Information about encoding modifiers is not provided in the specification. 37 | * `S_ATOMIC_*` instructions have a `VMEM` functional group (instead of `SMEM`). 38 | 39 | ### API and tools ### 40 | 41 | * Decoding of `MIMG` instructions (such as `IMAGE_STORE` and `IMAGE_LOAD`) may produce the wrong register indices for source vector register operands. 42 | * Decoding binary representation of certain RDNA™2 `MIMG`, `MUBUF` and `MTBUF` instructions may produce the wrong results. 43 | * Decoding `DS` instructions may return the wrong operands when decoded via `IsaDecoder::DecodeInstruction()` with an `uint64_t` argument. 44 | 45 | -------------------------------------------------------------------------------- /_clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: Google 2 | IndentWidth: 4 3 | UseTab: Never 4 | ColumnLimit: 160 5 | 6 | Language: Cpp 7 | AccessModifierOffset: -4 8 | BreakBeforeBraces: Custom 9 | BraceWrapping: 10 | AfterCaseLabel: true 11 | AfterClass: true 12 | AfterControlStatement: true 13 | AfterEnum: true 14 | AfterFunction: true 15 | AfterNamespace: true 16 | AfterObjCDeclaration: true 17 | AfterStruct: true 18 | AfterUnion: true 19 | AfterExternBlock: false 20 | BeforeCatch: true 21 | BeforeElse: true 22 | IndentBraces: false 23 | SplitEmptyFunction: true 24 | SplitEmptyRecord: true 25 | SplitEmptyNamespace: true 26 | ConstructorInitializerAllOnOneLineOrOnePerLine : false 27 | BreakConstructorInitializers: BeforeComma 28 | DerivePointerAlignment: false 29 | IndentCaseLabels: false 30 | NamespaceIndentation: All 31 | AlignConsecutiveAssignments: true 32 | AlignConsecutiveDeclarations: true 33 | AlignEscapedNewlines: Left 34 | AlignTrailingComments: true 35 | AlignOperands: true 36 | AllowShortFunctionsOnASingleLine: false 37 | AllowShortIfStatementsOnASingleLine: false 38 | AllowShortLoopsOnASingleLine: false 39 | AllowShortBlocksOnASingleLine: false 40 | ReflowComments: false 41 | SortIncludes: false 42 | SortUsingDeclarations: false 43 | BinPackArguments: false 44 | BinPackParameters: false 45 | ExperimentalAutoDetectBinPacking: false 46 | AllowAllParametersOfDeclarationOnNextLine: false 47 | -------------------------------------------------------------------------------- /build/prebuild_linux.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Set some defaults. 3 | BUILD_DIR="linux" 4 | 5 | # Create build directory. 6 | if [ ! -d $BUILD_DIR ]; then 7 | mkdir $BUILD_DIR 8 | fi 9 | 10 | # Read the custom path for tinyxml. 11 | for arg in "$@"; do 12 | case $arg in 13 | --tinyxml2_src_path=*) 14 | TINYXML_SRC_PATH="${arg#*=}" # Extract the value after '=' 15 | shift # Remove the argument from the list 16 | ;; 17 | *) 18 | echo "Unknown option: $arg" 19 | exit 1 20 | ;; 21 | esac 22 | done 23 | 24 | # Go to the build directory. 25 | cd $BUILD_DIR 26 | 27 | # Check if tinyxml2 needs to be overwritten. 28 | if [ -z "$TINYXML_SRC_PATH" ]; then 29 | # Use default tinyxml2. 30 | cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 ../../ 31 | else 32 | # Use the custom tinyxml2. 33 | cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=1 -DTINYXML_SRC_PATH=$TINYXML_SRC_PATH ../../ 34 | fi 35 | 36 | -------------------------------------------------------------------------------- /build/prebuild_windows.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | :: prebuild.bat --vs 2022 3 | SETLOCAL 4 | 5 | rem Print help message 6 | if "%1"=="-h" goto :print_help 7 | if "%1"=="-help" goto :print_help 8 | if "%1"=="--h" goto :print_help 9 | if "%1"=="--help" goto :print_help 10 | if "%1"=="/?" goto :print_help 11 | 12 | goto :start 13 | 14 | :print_help 15 | echo: 16 | echo This script generates Visual Studio project and solution files for IsaSpecManager on Windows. 17 | echo: 18 | echo Usage: prebuild.bat ^[options^] 19 | echo: 20 | echo Options: 21 | echo --cmake Path to cmake executable to use. If not specified, the cmake from PATH env variable will be used. 22 | echo --tinyxml2_src_path Path to TinyXML2 source. If not specified, the default TinyXML2 bundled with the isa_decoder will be used. 23 | echo --vs Microsoft Visual Studio version. Currently supported values are: "2015", "2017", "2019" and "2022". The default is "2022". 24 | echo --decoder_only Only include the decoder library for this project; skip the command line interface, examples and tests. 25 | echo: 26 | echo Examples: 27 | echo prebuild_windows.bat 28 | echo prebuild_windows.bat --vs 2022 29 | echo prebuild_windows.bat --vs 2022 --tinyxml2_src_path [path to custom tinyxml2] 30 | 31 | goto :exit 32 | 33 | :start 34 | set SCRIPT_DIR=%~dp0 35 | set CURRENT_DIR=%CD% 36 | 37 | rem Default values 38 | set CMAKE_PATH=cmake 39 | set VS_VER=2022 40 | set DECODER_ONLY= 41 | set TINYXML= 42 | 43 | :begin 44 | if [%1]==[] goto :start_cmake 45 | if "%1"=="--cmake" goto :set_cmake 46 | if "%1"=="--vs" goto :set_vs 47 | if "%1"=="--tinyxml2_src_path" goto :set_tinyxml2_src_path 48 | if "%1"=="--decoder_only" goto :set_decoder_only 49 | goto :bad_arg 50 | 51 | :set_cmake 52 | set CMAKE_PATH=%2 53 | goto :shift_2args 54 | 55 | :set_vs 56 | set VS_VER=%2 57 | goto :shift_2args 58 | 59 | :set_tinyxml2_src_path 60 | set TINYXML=-DTINYXML_SRC_PATH=%2 61 | goto :shift_2args 62 | 63 | :set_verbose 64 | @echo on 65 | goto :shift_arg 66 | 67 | :set_decoder_only 68 | set DECODER_ONLY="-DEXCLUDE_ISA_CLI_EXAMPLES_TESTS=ON" 69 | goto :shift_arg 70 | 71 | :shift_2args 72 | rem Shift to the next pair of arguments 73 | shift 74 | :shift_arg 75 | shift 76 | goto :begin 77 | 78 | :bad_arg 79 | echo Error: Unexpected argument: %1%. Aborting... 80 | exit /b 1 81 | 82 | :start_cmake 83 | set CMAKE_VSARCH= 84 | if "%VS_VER%"=="2015" ( 85 | set CMAKE_VS="Visual Studio 14 2015 Win64" 86 | ) else ( 87 | if "%VS_VER%"=="2017" ( 88 | set CMAKE_VS="Visual Studio 15 2017 Win64" 89 | ) else ( 90 | if "%VS_VER%"=="2019" ( 91 | set CMAKE_VS="Visual Studio 16 2019" 92 | set CMAKE_VSARCH=-A x64 93 | ) else ( 94 | if "%VS_VER%"=="2022" ( 95 | set CMAKE_VS="Visual Studio 17 2022" 96 | set CMAKE_VSARCH=-A x64 97 | ) else ( 98 | echo Error: Unknown VisualStudio version provided. Aborting... 99 | exit /b 1 100 | ) 101 | ) 102 | ) 103 | ) 104 | 105 | rem Create an output folder 106 | set VS_FOLDER=VS%VS_VER% 107 | set OUTPUT_FOLDER=%SCRIPT_DIR%windows\%VS_FOLDER% 108 | if not exist %OUTPUT_FOLDER% ( 109 | mkdir %OUTPUT_FOLDER% 110 | ) 111 | 112 | rem Invoke cmake with required arguments. 113 | echo: 114 | echo Running cmake to generate a VisualStudio solution... 115 | cd %OUTPUT_FOLDER% 116 | %CMAKE_PATH% %DECODER_ONLY% %TINYXML% -G %CMAKE_VS% %CMAKE_VSARCH% ..\..\.. 117 | if not %ERRORLEVEL%==0 ( 118 | echo "ERROR: cmake failed. Aborting..." 119 | exit /b 1 120 | ) 121 | cd %CURRENT_DIR% 122 | echo Done. 123 | -------------------------------------------------------------------------------- /documentation/cli_documentation.md: -------------------------------------------------------------------------------- 1 | # ISA Spec Manager CLI 2 | ISA Spec Manager CLI program is an example program that leverages IsaSpecApi. The main purpose of this program is to wrap the API and provide a platform to showcase the features of the API. 3 | 4 | ## Binary instruction decoding 5 | To decode an instruction that is represented in the binary (machine code) format using CLI, run the commands below. 6 | 7 | ```bash 8 | cd IsaSpecManager-Win64/cli 9 | ./IsaSpecCli.exe -x ../../Specification/xml/gfx11.xml -d BE804814 10 | ``` 11 | As can be seen from the command, `-x` flag should be followed by the path to the machine-readable XML specification. Next, `-d` flag should be followed by the instruction in the binary form. Note that the provided instruction should be encoded in the specified architecture. After running the command, the CLI outputs the following: 12 | 13 | ```bash 14 | Info: Parsing XML file... 15 | Info: XML parsing completed successfully. 16 | Info: Decoding... 17 | Info: Decoding completed successfully. 18 | 19 | Instruction: S_SETPC_B64 s20 20 | Description: 21 | Jump to a new location. Argument is a byte address of the 22 | instruction to jump to. 23 | 24 | Encoding: ENC_SOP1 25 | ENCODING [31:23] = 17d 26 | OP [15: 8] = 48 27 | SDST [22:16] = 0 28 | SSRC0 [ 7: 0] = 14 29 | ``` 30 | If decoded successfully, CLI outputs the instruction in an assembly form, description of the instruction and followed by the breakdown of the instruction's encoding. 31 | 32 | ## Requesting instruction information (by name) 33 | To retrieve information about a specific instruction from the spec, the name of the instruction could be provided to the CLI. Refer to the commands below. 34 | 35 | ```bash 36 | cd IsaSpecManager-Win64/cli 37 | ./IsaSpecCli.exe -x ../../Specification/xml/gfx11.xml -i s_setpc_b64 38 | ``` 39 | As can be seen from the command, `-x` flag should be followed by the path to the machine-readable XML specification. Next, `-i` flag should be followed by the name of the instruction which we are interested in. Note, that the requested instruction should be present in the specified architecture. After running the command, CLI outputs the following: 40 | 41 | ```bash 42 | Info: Parsing XML file... 43 | Info: XML parsing completed successfully. 44 | Info: Retrieving instruction information... 45 | Info: Instruction information retrieved successfully. 46 | 47 | Instruction: S_SETPC_B64 48 | Description: 49 | Jump to a new location. Argument is a byte address of the instruction to jump to. 50 | ``` 51 | If data was retrieved successfully, CLI outputs the full description of the instruction. 52 | -------------------------------------------------------------------------------- /documentation/isa_decoder/api_documentation.md: -------------------------------------------------------------------------------- 1 | # `IsaDecoder` documentation 2 | The `IsaDecoder` API makes it easier to perform common tasks with the AMD GPU machine-readable ISA specifications, such as reading the XML files, decoding instructions, and retrieving information about decoded instructions. 3 | 4 | This document describes the API. 5 | 6 | # API functions 7 | ## `amdisa::IsaDecoder::Initialize` 8 | ```c++ 9 | bool Initialize(const std::string& input_xml_file_path, std::string& err_message); 10 | ``` 11 | This routine initializes an `IsaDecoder` instance. It reads in a machine-readable XML ISA Specification and populates the internal data structures. 12 | 13 | ### Parameters 14 | parameter name | parameter type | description | input/output 15 | -|-|-|- 16 | input_xml_file_path | `const std::string&` | Path to the XML ISA Specification | input 17 | err_message | `std::string&` | Error message (set in case of a failure) | output 18 | 19 | ### Return value 20 | A boolean value: true on success, false otherwise. 21 | 22 | ### Example 23 | ```c++ 24 | #include "isa_decoder.h" 25 | 26 | int main () 27 | { 28 | amdisa::IsaDecoder spec_api; 29 | std::string err_message; 30 | bool is_init = spec_api.Initialize("C:/gfx11.xml", err_message); 31 | if (!is_init) 32 | { 33 | std::cerr << err_message << std::endl; 34 | } 35 | return (is_init ? 0 : -1); 36 | } 37 | ``` 38 | 39 | ## `amdisa::IsaDecoder::GetVersion` 40 | 41 | ```c++ 42 | std::string GetVersion() const 43 | ``` 44 | Gets the API version. 45 | 46 | ### Parameters 47 | No parameters accepted. 48 | 49 | ### Return value 50 | The function returns a std::string which contains the API version in format. 51 | 52 | ### Example 53 | ```c++ 54 | #include "isa_decoder.h" 55 | 56 | int main () 57 | { 58 | amdisa::IsaDecoder decoder_api; 59 | std::cout << "API version: "; 60 | std::cout << decoder_api.Major << "."; 61 | std::cout << decoder_api.Minor << "."; 62 | std::cout << decoder_api.Patch << "."; 63 | return 0; 64 | } 65 | ``` 66 | 67 | ## `amdisa::IsaDecoder::DecodeInstructionStream` 68 | ```c++ 69 | bool DecodeInstructionStream( 70 | const std::vector& machine_code_stream, 71 | std::vector& instruction_info_stream, 72 | std::string& err_message) const; 73 | ``` 74 | Decodes a sequence of binary instructions. 75 | 76 | ### Parameters 77 | parameter name | type | description | input/output 78 | -|-|-|- 79 | machine_code_stream | `const std::vector&` | Vector of encoded instructions in binary format. | input 80 | instruction_info_stream | `std::vector&` | Vector of InstructionInfoBundle structures that provides detailed information about each decoded instruction. Refer to [API structures](#api-structures) section for the definition the structure. | output 81 | err_message | `std::string&` | Error message (set in case of a failure) | output 82 | 83 | ### Return value 84 | A boolean value: true on success, false otherwise. 85 | 86 | ### Example 87 | ```c++ 88 | #include "isa_decoder.h" 89 | 90 | int main () 91 | { 92 | amdisa::IsaDecoder spec_api; 93 | std::string err_message; 94 | bool is_init = spec_api.Initialize("C:/gfx11.xml", err_message); 95 | if (is_init) 96 | { 97 | // Instructions in binary. 98 | std::vector instructions = {0xb0804006, 0xbefe0017}; 99 | 100 | // Structure to hold the result of the decode. 101 | std::vector instruction_infos; 102 | 103 | // Decode. 104 | bool is_decoded = amdisa::DecodeInstructionStream(instructions, 105 | instruction_infos, err_message); 106 | if (is_decoded) 107 | { 108 | // Do stuff... 109 | } 110 | else 111 | { 112 | std::cerr << err_message << std::endl; 113 | } 114 | } 115 | else 116 | { 117 | std::cerr << err_message << std::endl; 118 | } 119 | 120 | return (is_init && is_decoded) ? 0 : -1; 121 | } 122 | ``` 123 | 124 | ## `amdisa::IsaDecoder::DecodeInstruction` - binary 125 | ```c++ 126 | bool DecodeInstruction(uint64_t machine_code, 127 | InstructionInfoBundle& instruction_info, 128 | std::string& err_message) const; 129 | ``` 130 | Decodes a single instruction encoded in binary format. This API is limited to a 64-bit instruction. If the instruction of interest is longer than 64 bits, `amdisa::IsaDecoder::DecodeInstructionStream` should be used instead. 131 | 132 | ### Parameters 133 | parameter name | type | description | input/output 134 | -|-|-|- 135 | machine_code_stream | `uint64_t` | A single instruction encoded in binary. | input 136 | instruction_info_stream | `InstructionInfoBundle&` | A single `InstructionInfoBundle` structure that provides detailed information about the decoded instruction. Refer to [API structures](#api-structures) section for the definition the structure. | output 137 | err_message | `std::string&` | Error message (set in case of a failure) | output 138 | 139 | ### Return value 140 | A boolean value: true on success, false otherwise. 141 | 142 | ### Example 143 | ```c++ 144 | #include "isa_decoder.h" 145 | 146 | int main () 147 | { 148 | amdisa::IsaDecoder spec_api; 149 | std::string err_message; 150 | bool is_init = spec_api.Initialize("C:/gfx11.xml", err_message); 151 | if (is_init) 152 | { 153 | // Instructions in binary. 154 | uint64_t single_instruction = 0xb0804006;; 155 | 156 | // Structure to hold the result of the decode. 157 | InstructionInfoBundle single_instruction_info; 158 | 159 | // Decode. 160 | bool is_decoded = amdisa::DecodeInstruction( 161 | single_instruction, single_instruction_info, err_message); 162 | if (is_decoded) 163 | { 164 | // Do stuff... 165 | } 166 | else 167 | { 168 | std::cerr << err_message << std::endl; 169 | } 170 | } 171 | else 172 | { 173 | std::cerr << err_message << std::endl; 174 | } 175 | 176 | return (is_init && is_decoded) ? 0 : -1; 177 | } 178 | ``` 179 | 180 | ## `amdisa::IsaDecoder::DecodeInstruction` - textual 181 | ```c++ 182 | bool DecodeInstruction(const std::string& instruction_name, 183 | InstructionInfo& instruction_info, 184 | std::string& err_message) const; 185 | ``` 186 | Given the name of the instruction (also known as the opcode name), the function outputs the information about the instruction. 187 | 188 | ### Parameters 189 | parameter name | type | description | input/output 190 | -|-|-|- 191 | instruction_name| `const std::string&` | An instruction name as defined in ISA | input 192 | instruction_info | `InstructionInfo&` | A single `InstructionInfo` structure that give information about the instruction. Refer to [API structures](#api-structures) section for the definition the structure. | output 193 | err_message | `std::string&` | Error message (set in case of a failure) | output 194 | 195 | ### Example 196 | ```c++ 197 | #include "isa_decoder.h" 198 | 199 | int main () 200 | { 201 | amdisa::IsaDecoder spec_api; 202 | std::string err_message; 203 | bool is_init = spec_api.Initialize("C:/gfx11.xml", err_message); 204 | if (is_init) 205 | { 206 | // Structure to hold the result of the decode. 207 | InstructionInfo instruction_info; 208 | 209 | // Decode. 210 | bool is_decoded = amdisa::DecodeInstruction("S_MOV_B32", 211 | instruction_info, err_message); 212 | if (is_decoded) 213 | { 214 | // Do stuff... 215 | } 216 | else 217 | { 218 | std::cerr << err_message << std::endl; 219 | } 220 | } 221 | else 222 | { 223 | std::cerr << err_message << std::endl; 224 | } 225 | 226 | return (is_init && is_decoded) ? 0 : -1; 227 | } 228 | ``` 229 | 230 | ## `amdisa::IsaDecoder::GetDebugLog` 231 | ```c++ 232 | std::vector GetDebugLog() const; 233 | ``` 234 | Retrieves a log of error and warning messages generated by the `IsaDecoder` instance. It can be used for debugging purposes to review any issues encountered during the lifetime of the instance. 235 | 236 | ### Return value 237 | A `std::vector` of `std::string` containing error and warning messages. If no messages are logged, the vector will be empty. 238 | 239 | ### Example 240 | ```c++ 241 | #include "isa_decoder.h" 242 | #include 243 | 244 | int main () 245 | { 246 | amdisa::IsaDecoder spec_api; 247 | // Assume `Initialize` or other operations have been performed. 248 | 249 | // Retrieve and print internal messages or warnings if present. 250 | for (const std::string& message : spec_api.GetDebugLog()) 251 | { 252 | std::cout << message << std::endl; 253 | } 254 | 255 | return 0; 256 | } 257 | ``` 258 | --- 259 | 260 | # API structures 261 | API defines various struct in `isa_decoder.h`. 262 | 263 | ## `amdisa::InstructionInfo` 264 | Through this structure `IsaDecoder` communicates information about a single decoded instruction. 265 | 266 | ### Definition 267 | ```c++ 268 | struct InstructionInfo { 269 | // Name of the instruction (also known as the opcode). 270 | std::string instruction_name; 271 | 272 | // Description of an instruction. 273 | std::string instruction_description; 274 | 275 | // Encoding of an instruction. 276 | std::string encoding_name; 277 | 278 | // Description of the encoding an instruction belongs to. 279 | std::string encoding_description; 280 | 281 | // Human-readable information about all of the fields and corresponding 282 | // encoded field values as a single string. 283 | std::string encoding_layout; 284 | 285 | // Parsable information about all of the fields. 286 | std::vector encoding_fields; 287 | 288 | // All of the operands involved in a given instruction. 289 | std::vector instruction_operands; 290 | 291 | // Modifiers applied to the operands. 292 | std::vector operand_modifiers; 293 | 294 | // Semantic information of an instruction. 295 | InstructionSemanticInfo instruction_semantic_info; 296 | }; 297 | ``` 298 | 299 | This structure instantiates the hierarchy of other structures with self-explanatory struct names and member variable names. Please refer to `isa_decoder.h` for the definition of all structures. 300 | 301 | ## `amdisa::InstructionInfoBundle` 302 | This structure holds information about several instructions (two or more `InstructionInfo`). The reason why this is a vector is to support encodings that pack multiple instructions into a single instruction (although in most cases you should expect only a single instruction in the bundle). 303 | 304 | ### Definition 305 | ```c++ 306 | struct InstructionInfoBundle { 307 | std::vector bundle; 308 | }; 309 | ``` 310 | -------------------------------------------------------------------------------- /documentation/isa_decoder/api_tutorial.md: -------------------------------------------------------------------------------- 1 | # Tutorial: "Decoding RDNA Instructions with IsaDecoder" # 2 | 3 | ## Motivation ## 4 | 5 | AMD recently released its machine-readable GPU ISA specification - a set of XML files describing its RDNA and CDNA Instruction Set Architectures. While you can parse the XML files yourself, the easiest way to consume the specification is using the `IsaDecoder` API: Given an XML specification file, the API can read and parse it for you and even decode single instructions or whole shaders. 6 | 7 | This tutorial demonstrates how to use the `IsaDecoder` API to decode AMD GPU assembly provided in either binary or textual (disassembly) format. 8 | 9 | ## `IsaDecoder` ## 10 | 11 | The API allows you to decode either a single instruction or a whole shader/kernel. 12 | 13 | The source code for the API can be found on the [isa_spec_manager GitHub repository](https://github.com/GPUOpen-Tools/isa_spec_manager). 14 | 15 | ## Getting started - `IsaDecoder` ## 16 | 17 | Step 1: Instantiate `IsaDecoder`. 18 | 19 | `IsaDecoder` is defined under the namespace amdisa. For this tutorial, we define an `IsaDecoder` object named "api_decoder". 20 | ```c 21 | amdisa::IsaDecoder api_decoder; 22 | ``` 23 | 24 | Step 2: Initialize the `IsaDecoder` object with an input XML specification file. Make sure that the XML file you are using matches the GPU architecture that you are about to decode instructions for. For instance, use the MI-300 XML file to decode MI-300 kernels. 25 | 26 | The `Initialize()` API function reads and parses the given XML specification file. Upon success, the `IsaDecoder` object is ready to decode instructions. 27 | ```c 28 | bool is_success = api_decoder.Initialize(kPathToSpec, error_msg); 29 | ``` 30 | 31 | ## 1. Decoding a single instruction ## 32 | 33 | ### 1.1 Decoding a single instruction in binary format ### 34 | 35 | Consider the following binary representation of an RDNA instruction: `8BEA7E6A`. Let's use the API to decode it. 36 | 37 | Step 1: Create a variable to store the binary representation. 38 | ```c 39 | const std::string kStrSampleInstructionBinary = "8BEA7E6A"; 40 | ``` 41 | 42 | Step 2: Convert the binary representation to its decimal equivalent. 43 | 44 | We convert the hexadecimal value to its unsigned int (decimal) equivalent with the help of std::stringstream as shown below. This is, of course, only necessary for the sake of this example. In the wild, you will be able to use the API directly on binary machine code obtained from AMD GPU Code Objects. 45 | ```c 46 | std::stringstream IsaInstructionStream; 47 | IsaInstructionStream << kStrSampleInstructionBinary; 48 | uint64_t instruction_binary = 0; 49 | IsaInstructionStream >> std::hex >> instruction_binary; 50 | ``` 51 | 52 | **Note**: To use std::stringstream, we will have to ```#include ``` 53 | 54 | Step 3: Create an empty `InstructionInfoBundle`[2]. 55 | 56 | To obtain the decoded information, we pass an empty data structure `amdisa::InstructionInfoBundle`. 57 | ```c 58 | amdisa::InstructionInfoBundle instruction_info_bundle; 59 | ``` 60 | 61 | Step 4: Call the `DecodeInstruction()` API function. 62 | 63 | We then proceed to provide the decimal equivalent `instruction_binary`, `instruction_info_bundle`, and `error_msg` to `DecodeInstruction()` which returns true on successful decode and false if the decoding fails. 64 | ```c 65 | bool is_success = api_decoder.DecodeInstruction(instruction_binary, instruction_info_bundle, error_msg); 66 | ``` 67 | 68 | **Note**: It is possible to provide a decimal equivalent directly to the DecodeInstruction() API. Skip 2 & 3. 69 | 70 | Output: 71 | Instruction Name: S_AND_B64 72 | Instruction Description: Bitwise AND. 73 | Encoding Name: ENC_SOP2 74 | Encoding Description: SCALAR ALU OPERATIONS WITH ONE DESTINATION AND TWO SOURCES. 75 | ALLOWED PATTERNS: 76 | SOP2 (32 BITS) 77 | SOP2 + LITERAL (64 BITS) 78 | 79 | `8BEA7E6A` decodes to a scalar ALU instruction (`S_AND_B64`) that performs bitwise AND operation. The instruction's encoding is `ENC_SOP2` implying a scalar ALU operation with one destination and two sources. 80 | 81 | ### 1.2 Decoding a single instruction in texual format ### 82 | 83 | Now, let's learn how the API can be used to decode an instruction's disassembly to retrieve its human-readable description. Consider the following textual representation of an RDNA instruction: `v_mov_b32`. 84 | 85 | Step 1: Create a variable to store the instruction name. 86 | ```c 87 | const std::string kStrSampleInstruction = "v_mov_b32"; 88 | ``` 89 | 90 | Step 2: Create an empty `InstructionInfo`[1] struct variable. 91 | ```c 92 | amdisa::InstructionInfo instruction_info; 93 | ``` 94 | 95 | Step 3: Call the `DecodeInstruction()` API function. 96 | 97 | We then proceed to provide the instruction name `kStrSampleInstruction`, `instruction_info1, and `error_msg` to `DecodeInstruction()`. Returns true on successful decode and false if the decoding fails. The failure reason is populated in the error_msg. 98 | ```c 99 | bool is_success = api_decoder.DecodeInstruction(kStrSampleInstruction, instruction_info, error_msg); 100 | ``` 101 | 102 | Output: 103 | On a successful decode, we get the following information from instruction_info. 104 | 105 | Instruction Name: V_MOV_B32 106 | Instruction Description: Move data to a VGPR. 107 | 108 | ## 2. Decoding a whole shader ## 109 | 110 | ### 2.1 Decoding a whole shader in binary format ### 111 | 112 | The API accepts and decodes a whole shader in the form of binary stream of instructions. Let's have a look at the following binary stream of instructions: 113 | ``` 114 | `8BEA7E6A D6130002 00884D02` 115 | ``` 116 | 117 | Step 1: Create a variable to store the sample instructions in binary format. 118 | ```c 119 | std::string sample_instructions_binary = "8BEA7E6A D6130002 00884D02"; 120 | ``` 121 | 122 | Step 2: Convert the sample instructions to their respective binary format and store in a std::vector\. This is, of course, only necessary for the sake of this example. In practice you can use this API call directly on sequences of AMD GPU assembly instructions. 123 | ```c 124 | std::vector sample_instructions; 125 | std::stringstream SampleInstructionStream(sample_instructions_binary); 126 | uint32_t instruction_binary; 127 | while (SampleInstructionStream >> std::hex >> instruction_binary) { 128 | sample_instructions.push_back(instruction_binary); 129 | } 130 | ``` 131 | 132 | Step 3: Create a vector of `InstructionInfoBundle`[3]. 133 | To obtain the decoded information, we pass an empty vector of `amdisa::InstructionInfoBundle`. 134 | ```c 135 | std::vector instruction_info_bundle; 136 | ``` 137 | 138 | Step 4: Call the `DecodeInstructionStream()` API 139 | 140 | We then proceed to provide the vector of sample instructions in binary format `SampleInstructions`, `instruction_info_bundle`, and `error_msg` to `DecodeInstructionStream()` API. 141 | ```c 142 | bool is_success = api_decoder.DecodeInstructionStream(SampleInstructions, instruction_info_bundle, error_msg); 143 | ``` 144 | 145 | Output: 146 | Instruction Name: S_AND_B64 147 | Instruction Description: Bitwise AND. 148 | Encoding Name: ENC_SOP2 149 | 150 | Instruction Name: V_FMA_F32 151 | Instruction Description: Fused single precision multiply add. 152 | Encoding Name: ENC_VOP3 153 | 154 | **Note**: The `V_FMA_F32` instruction is represented using two dwords (2 x 32-bit). Thus, from the given sample instructions of the shader, two instructions are decoded. 155 | 156 | ### 2.2 Decoding a whole shader in disassembly format ### 157 | 158 | The API can also decode a whole shader in AMD's disassembly format. Consider decoding the shader disassembly file "example_shader_disassembly". 159 | 160 | Step 1: Create a variable to store the shader disassembly file path. 161 | ```c 162 | const std::string kPathToShaderFile = "/path/to/example_shader_disassembly"; 163 | ``` 164 | 165 | Step 2: Create a vector of `InstructionInfoBundle`[3] variable. 166 | To obtain the decoded information, we pass an empty data structure `amdisa::InstructionInfoBundle`. 167 | ```c 168 | amdisa::InstructionInfoBundle instruction_info_stream; 169 | ``` 170 | 171 | Step 3: Call the DecodeInstruction() API function. 172 | 173 | We then proceed to provide the path to the shader disassembly file, `instruction_info_strea`, `error_msg`, and `resolve_direct_branch_targets` to `DecodeShaderText()`. 174 | ```c 175 | bool is_success = api_decoder.DecodeShaderText(kPathToShaderFile, instruction_info_stream, error_msg, resolve_direct_branch_targets); 176 | ``` 177 | 178 | **Note**: `resolve_direct_branch_targets` is an optional parameter. Setting it to `true` enables determining the direct branch's target instruction's index in the `instruction_info_bundle` vector which will be available in the `InstructionInfo.instruction_semantic_info.branch_info` struct's member `branch_target_index`. For example, in the following shader: 179 | 180 | s_branch label_05F4 // 000000000000: BFA00004 181 | label_05E4: 182 | v_mov_b32 v28, 0 // 000000000004: 7E380280 183 | label_05F4: 184 | v_fma_f32 v0, s10, s10, v0 // 000000000008: D6130000 0400140A 185 | 186 | The target instruction index of the s_branch instruction will be 2, i.e, the third instruction v_fma_f32. Indexing in the instruction_info_bundle starts from 0. 187 | 188 | ## Appendix ## 189 | 190 | ### 1. amdisa::InstructionInfo ### 191 | 192 | This output data structure is used when we decode the instruction by name. 193 | 194 | amdisa::InstructionInfo struct type that consists of the following information: 195 | - Instruction 196 | - instruction_name: Instruction's name 197 | - instruction_description: Brief description about the instruction 198 | - Encoding 199 | - encoding_name: Instruction's encoding 200 | - encoding_description: Brief description about the encoding 201 | - encoding_fields: Information about the fields in the encoding 202 | - field_name 203 | - field_value 204 | - bit_count 205 | - bit_offset 206 | - encoding_layout: Representation of the encoding's layout 207 | - Operands (instruction_operands): Information about the instruction's operands 208 | - operand_name 209 | - operand_size 210 | - is_input 211 | - is_output 212 | - Modifiers (operand_modifiers): Information about the instruction's operand's modifiers 213 | - modifier_name 214 | - value 215 | - Semantics (instruction_semantic_info): Information about the instruction's semantics 216 | - is_program_terminator 217 | - is_immediately_executed 218 | - branch_info 219 | - is_branch 220 | - is_conditional 221 | - is_indirect 222 | - branch_offset 223 | - branch_target_PC 224 | - branch_target_index 225 | 226 | **Note**: This hierarchy resembles the nested structures (struct in a struct). 227 | 228 | For example, consider the instruction 'S_AND_B64', following information can be fetched on a successful decode. 229 | ``` 230 | Instruction Name: S_AND_B64 231 | Instruction Description: Bitwise AND. 232 | Encoding Name: ENC_SOP2 233 | Encoding Description: Scalar ALU operations with one destination and two sources. Allowed patterns: 234 | SOP2 (32 bits) 235 | SOP2 + LITERAL (64 bits) 236 | Encoding Layout: 237 | ENCODING [31:30] = 2 238 | OP [29:23] = 17 239 | SDST [22:16] = 6a 240 | SSRC0 [ 7: 0] = 6a 241 | SSRC1 [15: 8] = 7e 242 | 243 | Encoding Fields: 244 | Field Name Value Bit Count Bit Offset 245 | ENCODING 2 2 30 246 | OP 23 7 23 247 | SDST 106 7 16 248 | SSRC0 106 8 0 249 | SSRC1 126 8 8 250 | Instruction Operands: 251 | Operand Size Is_Input Is_Output 252 | vcc_lo 64 no yes 253 | vcc_lo 64 yes no 254 | exec_lo 64 yes no 255 | Operand Modifier: 256 | None 257 | Instruction Semantic Info: 258 | Is_Program_Terminator: no 259 | Is_Immediately_Executed: no 260 | Is_Branch: no 261 | Is_Conditional: no 262 | Is_Indirect: no 263 | Branch Offset: 65536 264 | Branch Target Index: -1 265 | ``` 266 | 267 | ### 2. amdisa::InstructionInfoBundle ### 268 | 269 | This output data structure is used when we decode the binary representation of the instruction. 270 | `amdisa::InstructionInfoBundle` is a vector of `amdisa::InstructionInfo`. The reason why this is a vector is to support encodings that pack multiple instructions into a single instruction (although in most cases you should expect only a single instruction in the bundle). 271 | 272 | ### 3. A vector of amdisa::InstructionInfoBundle ### 273 | 274 | This output vector is used when a stream of instructions is provided to decode. On a successful decode, the decoded instruction infos are populated in this vector in the same order as provided. The first instruction's info index in the vector is 0. -------------------------------------------------------------------------------- /documentation/isa_explorer/api_documentation.md: -------------------------------------------------------------------------------- 1 | # `IsaExplorer` Documentation 2 | 3 | `IsaExplorer` is a set of utility classes for exploring the AMD GPU ISA specification contents. This API has the ability to iterate over a large subset of the specification contents 4 | 5 | The `Spec` class is a top level user facing interface allowing access to different pieces of information about the specification. It allows users to load an XML-based ISA specification file and access detailed information about the architecture, data formats, instructions, and operand types defined in the ISA. 6 | 7 | ## Public Member Functions 8 | 9 | ### `bool Init(const std::string& input_xml_file_path, std::string& err_message) noexcept` 10 | 11 | Reads an XML file containing the ISA specification and populates the internal data structures. 12 | 13 | #### Parameters 14 | 15 | | Parameter Name | Type | Description | 16 | | --------------------- | -------------------- | ------------------------------------------------------------------------------ | 17 | | `input_xml_file_path` | `const std::string&` | Path to the XML file containing the ISA specification. | 18 | | `err_message` | `std::string&` | Reference to a string that will hold an error message if initialization fails. | 19 | 20 | #### Return Value 21 | 22 | Returns `true` if the XML file was successfully parsed and internal structures were initialized. Returns `false` otherwise. 23 | 24 | #### Example 25 | 26 | ```c++ 27 | #include "amdisa/isa_explorer.h" 28 | 29 | int main() { 30 | Spec isa_spec; 31 | std::string err_message; 32 | if (!isa_spec.Init("path/to/isa_spec.xml", err_message)) { 33 | std::cerr << "Initialization failed: " << err_message << std::endl; 34 | return -1; 35 | } 36 | return 0; 37 | } 38 | ``` 39 | 40 | --- 41 | 42 | ### `const Architecture& GetArchitecture() const noexcept` 43 | 44 | Retrieves the architecture object associated with the ISA. 45 | 46 | #### Return Value 47 | 48 | Returns a `const` reference to the `Architecture` object. 49 | 50 | #### Example 51 | 52 | ```c++ 53 | #include "amdisa/isa_explorer.h" 54 | 55 | int main() { 56 | Spec isa_spec; 57 | std::string err_message; 58 | if (isa_spec.Init("path/to/isa_spec.xml", err_message)) { 59 | const auto& arch = isa_spec.GetArchitecture(); 60 | // Use the architecture object... 61 | } 62 | return 0; 63 | } 64 | ``` 65 | 66 | --- 67 | 68 | ### `const std::map& GetDataFormats() const noexcept` 69 | 70 | Retrieves the data formats defined in the ISA. 71 | 72 | #### Return Value 73 | 74 | Returns a `const` reference to a map where the key is the name of the data format, and the value is the corresponding `DataFormat` object. 75 | 76 | #### Example 77 | 78 | ```c++ 79 | #include "amdisa/isa_explorer.h" 80 | 81 | int main() { 82 | Spec isa_spec; 83 | std::string err_message; 84 | if (isa_spec.Init("path/to/isa_spec.xml", err_message)) { 85 | const auto& data_formats = isa_spec.GetDataFormats(); 86 | // Use the data_format object... 87 | } 88 | return 0; 89 | } 90 | ``` 91 | 92 | --- 93 | 94 | ### `const std::map& GetInstructions() const noexcept` 95 | 96 | Retrieves the instructions defined in the ISA. 97 | 98 | #### Return Value 99 | 100 | Returns a `const` reference to a map where the key is the instruction name, and the value is the corresponding `Instruction` object. 101 | 102 | #### Example 103 | 104 | ```c++ 105 | #include "amdisa/isa_explorer.h" 106 | 107 | int main() { 108 | Spec isa_spec; 109 | std::string err_message; 110 | if (isa_spec.Init("path/to/isa_spec.xml", err_message)) { 111 | const auto& instructions = isa_spec.GetInstructions(); 112 | // Use the instructions object... 113 | } 114 | return 0; 115 | } 116 | ``` 117 | 118 | --- 119 | 120 | ### `const std::map& GetOperandTypes() const noexcept` 121 | 122 | Retrieves the operand types defined in the ISA. 123 | 124 | #### Return Value 125 | 126 | Returns a `const` reference to a map where the key is the name of the operand type, and the value is the corresponding `OperandType` object. 127 | 128 | #### Example 129 | 130 | ```c++ 131 | #include "amdisa/isa_explorer.h" 132 | 133 | int main() { 134 | Spec isa_spec; 135 | std::string err_message; 136 | if (isa_spec.Init("path/to/isa_spec.xml", err_message)) { 137 | const auto& operand_types = isa_spec.GetOperandTypes(); 138 | // Use the operand_types object... 139 | } 140 | return 0; 141 | } 142 | ``` 143 | -------------------------------------------------------------------------------- /documentation/isa_explorer/api_tutorial.md: -------------------------------------------------------------------------------- 1 | # Tutorial: Exploring AMD ISA Instructions Using `IsaExplorer` API 2 | 3 | ## Introduction 4 | 5 | This tutorial demonstrates how to use the `amdisa::explorer::Spec` API to load an AMD GPU ISA specification file and query information about instructions. The program initializes the ISA specification, retrieves details about a specific instruction (`V_MOV_B32`), and randomly selects another instruction to display. By following this guide, you'll learn to leverage the `Spec` API for exploring AMD ISA. 6 | 7 | --- 8 | 9 | ## Prerequisites 10 | 11 | Before running the code, ensure you have: 12 | 13 | 1. **AMD ISA Specification File:** Obtain the XML specification file for the target GPU architecture. 14 | 2. **C++ Development Environment:** A compiler supporting C++11 or later and the required libraries for the `amdisa` namespace. 15 | 3. **Utility Functions:** The `print_instruction` function must be defined to display instruction details. You can create it to suit your display needs. 16 | 17 | --- 18 | 19 | ## Walkthrough 20 | 21 | ### 1. Initializing the `Spec` Object 22 | 23 | The `Spec` object from the `amdisa::explorer` namespace is used to load and interact with the ISA specification. 24 | 25 | ```cpp 26 | amdisa::explorer::Spec explorer; 27 | std::string err_message; 28 | bool is_init = explorer.Init(kPathToSpec, err_message); 29 | 30 | if (!is_init) 31 | { 32 | std::cerr << err_message << std::endl; 33 | return -1; 34 | } 35 | ``` 36 | 37 | - The `Init` function reads the XML specification file and checks for errors. 38 | - If initialization fails, an error message is printed, and the program exits. 39 | 40 | ### 2. Looking Up a Specific Instruction 41 | 42 | The `GetInstructions` method retrieves a map of all instructions available in the specification. The program queries for the `V_MOV_B32` instruction. 43 | 44 | ```cpp 45 | auto v_mov_b32 = explorer.GetInstructions().at("V_MOV_B32"); 46 | print_instruction(v_mov_b32); 47 | ``` 48 | 49 | The instruction data is passed to the `print_instruction` function, which should format and display the information. 50 | 51 | ### 3. Randomly Selecting an Instruction 52 | 53 | Alternatively, you can iterate over the map: 54 | 55 | ```cpp 56 | std::random_device rd; 57 | std::mt19937 gen(rd()); 58 | std::uniform_int_distribution dist(0, explorer.GetInstructions().size() - 1); 59 | 60 | auto it = explorer.GetInstructions().begin(); 61 | std::advance(it, dist(gen)); 62 | print_instruction(it->second); 63 | ``` 64 | 65 | - **Random Device and Generator:** Creates a random number generator seeded with a hardware-based random device. 66 | - **Uniform Distribution:** Ensures the random number falls within the valid range of instruction indices. 67 | - **Iterator Advancement:** Randomly selects an instruction by advancing the iterator to the generated index. 68 | 69 | The selected instruction is printed using the `print_instruction` function. 70 | 71 | As an exmple, you can use the following print function: 72 | 73 | ```cpp 74 | static void print_instruction(const amdisa::explorer::Instruction& instruction) 75 | { 76 | std::cout << "Name: " << instruction.Name() << std::endl; 77 | std::cout << "\tDescription: " << instruction.Description() << std::endl; 78 | std::cout << "\tIsBranch ?: " << instruction.IsBranch() << std::endl; 79 | std::cout << "\tIsConditionalBranch ?: " << instruction.IsConditionalBranch() << std::endl; 80 | std::cout << "\tIsIndirectBranch ?: " << instruction.IsIndirectBranch() << std::endl; 81 | std::cout << "\tFunctionalGroup: " << instruction.FuncGroup()->Name() << std::endl; 82 | std::cout << "\t\t Description: " << instruction.FuncGroup()->Description() << std::endl << std::endl; 83 | std::cout << "\tFunctionalSubgroup: " << instruction.FuncSubgroup()->Name() << std::endl; 84 | } 85 | ``` -------------------------------------------------------------------------------- /documentation/unit_tests_documentation.md: -------------------------------------------------------------------------------- 1 | # `Unit Tests` Documentation # 2 | 3 | ## Description ## 4 | Unit tests are defined for functionality check and error handling coverage while using the ISASPEC Decoder API. The unit tests implementation is based on the `catch2`(v2.13.10) testing framework. More on catch2 hereq: https://github.com/catchorg/Catch2. 5 | 6 | ## Tests Execution ## 7 | Upon building the `amdisa_tests` target, the executable `"amdisa_tests.exe"` for windows and `"amdisa_tests.so"` for linux is generated in the output directory. 8 | 9 | usage: 10 | amdisa_test.exe [ ... ] options\ 11 | where options are:\ 12 | -?, -h, --help; Display usage information \ 13 | -I, --spec \; Path to the AMDISA XML specification [REQUIRED] \ 14 | -F, --disassembly \; Path to the binary disassembly input file [OPTIONAL] 15 | 16 | The unit tests are performed on the ISA XML specification provided. The relevant unit tests are executed for the ISA Architecture as described by the XML specification. The binary disassembly input file is only required for the tests that validate the decoder API for a complete shader disassembly decode. 17 | 18 | ## Tests Output ## 19 | - Upon success, no assertion errors are observed.\ 20 | Success message: All tests passed 21 | 22 | - Upon failure, assertion errors are raised. Also, the failing test condition and test description are described.\ 23 | For example, 24 | ``` 25 | ------------------------------------------------------------------------------- 26 | Test to decode of a single instruction binary 27 | ------------------------------------------------------------------------------- 28 | FAILED: 29 | REQUIRE( info[0].bundle[0].instruction_name == "S_ADD_U32" ) 30 | with expansion: 31 | "S_ADD_CO_U32" == "S_ADD_U32" 32 | 33 | test cases: 8 | 6 passed | 2 failed 34 | ``` 35 | 36 | ## Unit Tests Description ## 37 | 38 | ### 1. XML Spec Initialization Tests ### 39 | 40 | #### 1.1 XML Spec Initialize #### 41 | Tests the successful initialization of the provided AMDISA specification xml. 42 | 43 | #### 1.2 Fail Test: XML Spec Initialize ### 44 | Tests the API for failure handling due to failied initialization of the provided AMDISA specification xml. 45 | 46 | ### 2. Decode Single Instruction Tests ### 47 | 48 | #### 2.1 Decode single instruction by name #### 49 | Tests the decoding of a single instruction by instruction name. 50 | 51 | #### 2.2 Decode single instruction using binary #### 52 | Tests the decoding of a single instruction using the instruction's binary representation (single dword). 53 | 54 | #### 2.3 Decode an instruction stream #### 55 | Tests the decoding of an instruction stream of an instruction represented with multiple dwords. 56 | 57 | ### 3. Decode Shader Disassembly Tests ### 58 | 59 | #### 3.1 Test to decode of a shader disassembly text #### 60 | Tests the decoding of a shader disassembly text. 61 | 62 | #### 3.2 Test to fail decode of a shader disassembly text #### 63 | Tests the API for failure handling due to failied decoding of a shader disassembly text. 64 | 65 | #### 3.3 Test to fail decode of a shader disassembly file #### 66 | Tests the API for failure handling due to failied decoding of a shader disassembly file. 67 | 68 | 69 | -------------------------------------------------------------------------------- /include/amdisa/api_version.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | #ifndef API_VERSION_H_ 5 | #define API_VERSION_H_ 6 | 7 | // C++ libraries. 8 | #include 9 | #include 10 | 11 | // IsaDecoder version. 12 | #define AMDISA_DECODE_API_VERSION_MAJOR 1 13 | #define AMDISA_DECODE_API_VERSION_MINOR 1 14 | #define AMDISA_DECODE_API_VERSION_PATCH 0 15 | 16 | // IsaExplorer version. 17 | #define AMDISA_EXPLORE_API_VERSION_MAJOR 1 18 | #define AMDISA_EXPLORE_API_VERSION_MINOR 0 19 | #define AMDISA_EXPLORE_API_VERSION_PATCH 0 20 | 21 | namespace amdisa 22 | { 23 | // Compatibility check related code. 24 | static const char* kStringErrorNotCompatibleXml = "Error: Unsupported XML schema version. Check for compatible XML schema. Please refer to XML schema changelog or API release notes for more details."; 25 | static const char* kStringWarningPartiallyCompatibleXmlPrefix = "Warning: detected XML schema version "; 26 | static const char* kStringWarningPartiallyCompatibleXmlSuffix = " which does not support certain features that are supported by this API version. Please refer to XML schema changelog or API release notes for more details."; 27 | 28 | // Structure to return API version. 29 | class ApiVersion 30 | { 31 | public: 32 | static int GetMajor() 33 | { 34 | return AMDISA_DECODE_API_VERSION_MAJOR; 35 | } 36 | 37 | static int GetMinor() 38 | { 39 | return AMDISA_DECODE_API_VERSION_MINOR; 40 | } 41 | 42 | static int GetPatch() 43 | { 44 | return AMDISA_DECODE_API_VERSION_PATCH; 45 | } 46 | 47 | static std::string GetVersion() 48 | { 49 | std::stringstream api_version; 50 | api_version << GetMajor() << "." << GetMinor() << "." << GetPatch(); 51 | return api_version.str(); 52 | } 53 | 54 | static bool IsAtLeast(int major, int minor, int patch) 55 | { 56 | bool is_older = false; 57 | is_older = 58 | (major < GetMajor() || (major == GetMajor() && minor < GetMinor()) || (major == GetMajor() && minor == GetMinor() && patch < GetPatch())); 59 | return !is_older; 60 | } 61 | 62 | static bool IsCompatible(const std::string& xml_schema_version, std::string& err_message) 63 | { 64 | if (xml_schema_version < GetVersion()) 65 | { 66 | std::stringstream err_message_ss; 67 | err_message_ss << kStringWarningPartiallyCompatibleXmlPrefix << xml_schema_version << kStringWarningPartiallyCompatibleXmlSuffix; 68 | err_message = err_message_ss.str(); 69 | } 70 | return true; 71 | } 72 | }; 73 | 74 | namespace explorer 75 | { 76 | // Structure to return API version. 77 | class ApiVersion 78 | { 79 | public: 80 | static int GetMajor() 81 | { 82 | return AMDISA_EXPLORE_API_VERSION_MAJOR; 83 | } 84 | 85 | static int GetMinor() 86 | { 87 | return AMDISA_EXPLORE_API_VERSION_MINOR; 88 | } 89 | 90 | static int GetPatch() 91 | { 92 | return AMDISA_EXPLORE_API_VERSION_PATCH; 93 | } 94 | 95 | static std::string GetVersion() 96 | { 97 | std::stringstream api_version; 98 | api_version << GetMajor() << "." << GetMinor() << "." << GetPatch(); 99 | return api_version.str(); 100 | } 101 | 102 | static bool IsAtLeast(int major, int minor, int patch) 103 | { 104 | bool is_older = false; 105 | is_older = 106 | (major < GetMajor() || (major == GetMajor() && minor < GetMinor()) || (major == GetMajor() && minor == GetMinor() && patch < GetPatch())); 107 | return !is_older; 108 | } 109 | 110 | static bool IsCompatible(const std::string& xml_schema_version, std::string& err_message) 111 | { 112 | // IsaExplorer supports all currently released XML specifications. 113 | return true; 114 | } 115 | }; 116 | } 117 | } // namespace amdisa 118 | 119 | #endif // API_VERSION_H_ 120 | -------------------------------------------------------------------------------- /include/amdisa/isa_decoder.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | #ifndef ISA_DECODER_H_ 5 | #define ISA_DECODER_H_ 6 | 7 | // C++ libraries. 8 | #include 9 | #include 10 | #include 11 | 12 | namespace amdisa 13 | { 14 | // Supported architectures. 15 | enum class GpuArchitecture 16 | { 17 | kUnknown, 18 | kRdna1, 19 | kRdna2, 20 | kRdna3, 21 | kRdna3_5, 22 | kRdna4, 23 | kCdna1, 24 | kCdna2, 25 | kCdna3 26 | }; 27 | 28 | // Constants. 29 | static const uint32_t kBranchOffsetOutOfRange = (1 << 16); 30 | static const uint64_t kInvalidBranchTarget = UINT64_MAX; 31 | 32 | // Instruction's functional group. 33 | enum class kFunctionalGroup 34 | { 35 | kFunctionalGroupUnknown, // Unknown 36 | kFunctionalGroupSalu, // Scalar ALU 37 | kFunctionalGroupSmem, // Scalar Memory 38 | kFunctionalGroupValu, // Vector ALU 39 | kFunctionalGroupVmem, // Vector Memory 40 | kFunctionalGroupExport, // Export 41 | kFunctionalGroupBranch, // Branch 42 | kFunctionalGroupMessage, // Message 43 | kFunctionalGroupWaveControl, // Wave Control 44 | kFunctionalGroupTrap // Trap 45 | }; 46 | 47 | static constexpr const char* kFunctionalGroupName[] = { 48 | "Unknown", // Unknown 49 | "Scalar ALU", // Scalar ALU 50 | "Scalar Memory", // Scalar Memory 51 | "Vector ALU", // Vector ALU 52 | "Vector Memory", // Vector Memory 53 | "Export", // Export 54 | "Branch", // Branch 55 | "Message", // Message 56 | "Wave Control", // Wave Control 57 | "Trap" // Trap 58 | }; 59 | 60 | // Instruction's functional group's subgroup. 61 | enum class kFunctionalSubgroup 62 | { 63 | kFunctionalSubgroupUnknown, // Unknown 64 | kFunctionalSubgroupFloatingPoint, // Floating Point 65 | kFunctionalSubgroupBuffer, // Buffer 66 | kFunctionalSubgroupTexture, // Texture 67 | kFunctionalSubgroupLoad, // Load 68 | kFunctionalSubgroupStore, // Store 69 | kFunctionalSubgroupSample, // Sample 70 | kFunctionalSubgroupBvh, // BVH 71 | kFunctionalSubgroupAtomic, // Atomic 72 | kFunctionalSubgroupFlat, // Flat 73 | kFunctionalSubgroupDataShare, // Data Share 74 | kFunctionalSubgroupStatic, // Static 75 | kFunctionalSubgroupMFMA, // MFMA 76 | kFunctionalSubgroupWMMA, // WMMA 77 | kFunctionalSubgroupTranscendental // Transcendental 78 | }; 79 | 80 | static constexpr const char* kFunctionalSubgroupName[] = { 81 | "Unknown", // Unknown 82 | "Floating Point", // Floating Point 83 | "Buffer", // Buffer 84 | "Texture", // Texture 85 | "Load", // Load 86 | "Store", // Store 87 | "Sample", // Sample 88 | "BVH", // BVH 89 | "Atomic", // Atomic 90 | "Flat", // Flat 91 | "Data Share", // Data Share 92 | "Static" // Static 93 | "MFMA", // MFMA 94 | "WMMA", // WMMA 95 | "Transcendental" // Transcendental 96 | }; 97 | 98 | // OperandModifier provides information about an input/output modifier. 99 | struct OperandModifer 100 | { 101 | std::string modifier_name; 102 | uint32_t value = 0; 103 | }; 104 | 105 | // EncodingField provides information about a single field of an instruction's encoding. 106 | // For example, OP is a field that encodes the opcode of a specific instruction. 107 | // InstructionInfo object contains a vector of EncodingFields that provide 108 | // information about every single field of the encoding. 109 | struct EncodingField 110 | { 111 | std::string field_name; 112 | uint64_t field_value = 0; 113 | 114 | // Size of the field. 115 | uint64_t bit_count = 0; 116 | 117 | // Position of the field in the encoding. 118 | uint64_t bit_offset = 0; 119 | }; 120 | 121 | // InstructionOperand provides information about a single operand of an 122 | // instruction. InstructionInfo contains a vector of InstructionOperands 123 | // that provide information about operands involved in a given instruction. 124 | struct InstructionOperand 125 | { 126 | // Name of the operand. For example: v1, s1, or literals. 127 | std::string operand_name; 128 | 129 | // Size of the operand. 130 | uint32_t operand_size = 0; 131 | 132 | // True if the operand is an input to an instruction (source). 133 | bool is_input = false; 134 | 135 | // True if the operand is an output of an instruction (destination). 136 | bool is_output = false; 137 | }; 138 | 139 | struct BranchInfo 140 | { 141 | // True if the instruction is a branch, false otherwise. 142 | bool is_branch = false; 143 | 144 | // True if the branch is conditional, false otherwise. 145 | bool is_conditional = false; 146 | 147 | // True if the branch is indirect, false otherwise. 148 | bool is_indirect = false; 149 | 150 | // True if the branch is direct. 151 | bool IsDirect() const; 152 | 153 | // Branch offset for direct branches (offset is embedded in the instruction). 154 | int32_t branch_offset = kBranchOffsetOutOfRange; 155 | 156 | // Direct branch target's PC (program counter). 157 | std::string branch_target_pc; 158 | 159 | // Direct branch target's label (if applicable). 160 | // When the decoded data is retrieved from disassembly, 161 | // the label representing the branch target will be stored here. 162 | std::string branch_target_label; 163 | 164 | // Direct branch target's index in the InstructionInfoBundle. 165 | uint64_t branch_target_index = kInvalidBranchTarget; 166 | }; 167 | 168 | // InstructionSemanticInfo provides behavioral information of an instruction. 169 | struct InstructionSemanticInfo 170 | { 171 | // Branch related information. 172 | BranchInfo branch_info; 173 | 174 | // True if this instruction indicates the end of the program and false 175 | // otherwise. 176 | bool is_program_terminator = false; 177 | 178 | // True if this instruction is executed directly by each wave's instruction 179 | // buffer. 180 | bool is_immediately_executed = false; 181 | }; 182 | 183 | struct FunctionalGroupSubgroupInfo 184 | { 185 | std::string description; 186 | kFunctionalGroup IsaFunctionalGroup = kFunctionalGroup::kFunctionalGroupUnknown; 187 | kFunctionalSubgroup IsaFunctionalSubgroup = kFunctionalSubgroup::kFunctionalSubgroupUnknown; 188 | }; 189 | 190 | // InstructionInfo is a structure that gets populated as a result of API 191 | // request. 192 | struct InstructionInfo 193 | { 194 | // Name of the instruction. 195 | std::string instruction_name; 196 | 197 | // Aliased instruction names. 198 | std::vector aliased_names; 199 | 200 | // Description of an instruction. 201 | std::string instruction_description; 202 | 203 | // Encoding of an instruction. 204 | std::string encoding_name; 205 | 206 | // Description of the encoding an instruction belongs to. 207 | std::string encoding_description; 208 | 209 | // Human-readable information about all of the fields and corresponding 210 | // encoded field values as a single string. 211 | std::string encoding_layout; 212 | 213 | // Information about the instruction's fields. 214 | std::vector encoding_fields; 215 | 216 | // The operands involved in a given instruction. 217 | std::vector instruction_operands; 218 | 219 | // Modifiers applied to the operands. 220 | std::vector operand_modifiers; 221 | 222 | // Semantic information of an instruction. 223 | InstructionSemanticInfo instruction_semantic_info; 224 | 225 | // Instruction's functional subgroup. 226 | FunctionalGroupSubgroupInfo functional_group_subgroup_info; 227 | }; 228 | 229 | // InstructionInfoBundle is one or more InstructionInfo objects 230 | // that were generated as a result of the decode of a single 231 | // binary encoded instruction. Certain encodings decode more than 232 | // a single instruction, and are therefore decoded into multiple 233 | // instructions. The purpose of this structure is to bundle such 234 | // instructions together. 235 | struct InstructionInfoBundle 236 | { 237 | std::vector bundle; 238 | }; 239 | 240 | class IsaDecoder 241 | { 242 | public: 243 | /* 244 | * Initialize -- 245 | * 246 | * Reads in XML ISA specification and populates the internal structures. 247 | * 248 | * Returns true if the spec was successfully read, or false otherwise 249 | * with the error message in err_message. 250 | */ 251 | bool Initialize(const std::string& input_xml_file_path, std::string& err_message); 252 | 253 | /* 254 | * GetVersion -- 255 | * 256 | * Return a ".." string that represents the version of this API. 257 | * For more details or preprocessor access to version components, please see api_version.h. 258 | */ 259 | std::string GetVersion() const; 260 | 261 | /* 262 | * GetArchitecture -- 263 | * 264 | * Return the architecture enumaration. 265 | */ 266 | GpuArchitecture GetArchitecture() const; 267 | 268 | /* 269 | * DecodeInstruction -- 270 | * 271 | * Accepts a single machine code. This function is limited to 64-bit wide 272 | * instructions or shorter. Use DecodeInstructionStream function for longer 273 | * instructions. 274 | * 275 | * Returns true if the provided machine_code (binary representation of the 276 | * instruction) was decoded successfully and populates instruction_info with 277 | * corresponding information about the decoded instruction. 278 | * Returns false otherwise with the error string output. 279 | */ 280 | bool DecodeInstruction(uint64_t machine_code, InstructionInfoBundle& instruction_info, std::string& err_message) const; 281 | 282 | /* 283 | * DecodeInstruction -- 284 | * 285 | * Accepts a string that represents an instruction name. 286 | * 287 | * Returns true if the provided instruction was decoded successfully and 288 | * populates instruction_info with corresponding information about the 289 | * decoded instruction. Returns false otherwise with the error string output. 290 | */ 291 | bool DecodeInstruction(const std::string& instruction_name, InstructionInfo& instruction_info, std::string& err_message) const; 292 | 293 | /* 294 | * DecodeInstructionStream -- 295 | * 296 | * Accepts instruction stream as a vector of DWORDs. 297 | * 298 | * Returns true if all of the instructions were successfully decoded, or false 299 | * even if a single DWORD from instruction stream fails to be decoded. On a 300 | * successful decode, the function outputs a vector of InstructionInfoGroup. 301 | * Each of the objects in the vector correspond to a decoded instruction in 302 | * the input instruction stream. 303 | */ 304 | bool DecodeInstructionStream(const std::vector& machine_code_stream, 305 | std::vector& instruction_info_stream, 306 | std::string& err_message) const; 307 | 308 | /* 309 | * DecodeShaderDisassemblyText -- 310 | * 311 | * Accepts a shader disassembly text (SP3/LLVM). 312 | * 313 | * Returns true if all the instructions present in the provided shader 314 | * disassembly text were successfully extracted and decoded, or false 315 | * otherwise (even if the decoding of a single instruction fails - false 316 | * is returned). The failure reason is populated in the err_message. 317 | * On successful decode, the function outputs a vector of 318 | * InstructionInfoBundle with the decoded information of all the instructions. 319 | * 320 | * Additional Option: resolve_direct_branch_targets 321 | * (optional, default - false and skipped) 322 | * Setting the resolve_direct_branch_targets to true enables determining 323 | * the direct branch's target instruction's index in the 324 | * instruction_info_bundle vector which will be available in the 325 | * InstructionInfo.instruction_semantic_info.branch_info's struct member 326 | * branch_target_index 327 | */ 328 | bool DecodeShaderDisassemblyText(const std::string& shader_disassembly_text, 329 | std::vector& instruction_info_stream, 330 | std::string& err_message, 331 | bool resolve_direct_branch_targets) const; 332 | 333 | /* 334 | * DecodeShaderDisassemblyFile -- 335 | * 336 | * Accepts a shader disassembly file (SP3/LLVM). 337 | * 338 | * Returns true if all the instructions present in the provided shader 339 | * disassembly file were successfully extracted and decoded, or false 340 | * otherwise (even if the decoding of a single instruction fails) and 341 | * the failure reason is populated in the err_message. On successful decode, 342 | * the function outputs a vector of InstructionInfoBundle with the decoded 343 | * information of all the instructions. 344 | * 345 | * Additional Option: resolve_direct_branch_targets 346 | * (optional, default - false and skipped) 347 | * Setting the resolve_direct_branch_targets to true enables determining 348 | * the direct branch's target instruction's index in the 349 | * instruction_info_bundle vector which will be available in the 350 | * InstructionInfo.instruction_semantic_info.branch_info's struct member 351 | * branch_target_index 352 | */ 353 | bool DecodeShaderDisassemblyFile(const std::string& shader_disassembly_file, 354 | std::vector& instruction_info_stream, 355 | std::string& err_message, 356 | bool resolve_direct_branch_targets) const; 357 | /* 358 | * GetDebugLog -- 359 | * 360 | * Retrieves a log of error and warning messages generated by this instance. 361 | * This function can be used for debugging purposes. 362 | * 363 | * Returns a vector of string messages if anything was logged. 364 | */ 365 | std::vector GetDebugLog() const; 366 | 367 | IsaDecoder() = default; 368 | ~IsaDecoder(); 369 | 370 | private: 371 | class IsaDecoderImpl; 372 | IsaDecoderImpl* api_impl_ = nullptr; 373 | }; 374 | 375 | // Convenience API for handling multiple architectures. 376 | class DecodeManager 377 | { 378 | public: 379 | /** 380 | * Initialize -- 381 | * 382 | * Accepts the vector of file paths to specs and 383 | * initializes the API with the provided spec files. 384 | * 385 | * Returns 'true' if the initialization is successful. 386 | * Returns 'false' if any error occurs during initialization. 387 | */ 388 | bool Initialize(const std::vector& input_spec_file_paths, std::string& err_message); 389 | 390 | /** 391 | * GetDecoder -- 392 | * 393 | * Accepts the architecture enum for which amdisa::IsaDecoder is requested. 394 | * 395 | * Returns pointer to the decoder if the provided architecture was found, and the nullptr otherwise. 396 | */ 397 | std::shared_ptr GetDecoder(GpuArchitecture architecture) const; 398 | 399 | DecodeManager() = default; 400 | ~DecodeManager(); 401 | 402 | private: 403 | struct DecodeManagerImpl; 404 | DecodeManagerImpl* manager_impl_ = nullptr; 405 | }; 406 | } // namespace amdisa 407 | #endif // ISA_DECODER_H_ 408 | -------------------------------------------------------------------------------- /source/common/amdisa_expression_tree_consts.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | #ifndef AMDISA_EXPRESSION_TREE_CONSTS_H_ 5 | #define AMDISA_EXPRESSION_TREE_CONSTS_H_ 6 | 7 | // C++ libraries. 8 | #include 9 | #include 10 | 11 | namespace amdisa 12 | { 13 | // Expression tree node type enum. 14 | enum class ExpressionTreeNodes 15 | { 16 | kLiteral, 17 | kId, 18 | kComment, 19 | kReturnType, 20 | kTypeTree, 21 | kSubexpression, 22 | kUndefined 23 | }; 24 | 25 | // Type tree enum. 26 | enum class TypeTreeNodes 27 | { 28 | kBaseType, 29 | kArrayType, 30 | kLambdaType, 31 | kUndefined 32 | }; 33 | 34 | // JSON leaf node identifiers. 35 | static const char* kJsonLiteralIdentifier = "'lit"; 36 | static const char* kJsonValueTypeIdentifier = "'ty"; 37 | static const char* kJsonIdIdentifier = "'id"; 38 | static const char* kJsonCommentIdentifier = ":comment"; 39 | 40 | // Return type. 41 | static const char* kReturnTypeIdentifier = "'ret"; 42 | 43 | // XML leaf node identifiers. 44 | static const char* kXmlLiteralIdentifier = "Literal"; 45 | static const char* kXmlValueTypeIdentifier = "ValueType"; 46 | static const char* kXmlIdIdentifier = "Id"; 47 | static const char* kXmlCommentIdentifier = "Comment"; 48 | static const char* kXmlReturnTypeIdentifier = "ReturnType"; 49 | 50 | // Map from JSON expression tree string names to enum. 51 | static const std::map kMapJsonExpressionTreeNodeNamesToEnum = { 52 | {kJsonLiteralIdentifier, ExpressionTreeNodes::kLiteral}, 53 | {kReturnTypeIdentifier, ExpressionTreeNodes::kReturnType}, 54 | {kJsonValueTypeIdentifier, ExpressionTreeNodes::kTypeTree}, 55 | {kJsonIdIdentifier, ExpressionTreeNodes::kId}, 56 | {kJsonCommentIdentifier, ExpressionTreeNodes::kComment}, 57 | }; 58 | 59 | // Map from XML expression tree string names to enum. 60 | static const std::map kMapXmlExpressionTreeNodeNamesToEnum = { 61 | {kXmlLiteralIdentifier, ExpressionTreeNodes::kLiteral}, 62 | {kXmlValueTypeIdentifier, ExpressionTreeNodes::kTypeTree}, 63 | {kXmlIdIdentifier, ExpressionTreeNodes::kId}, 64 | {kXmlCommentIdentifier, ExpressionTreeNodes::kComment}, 65 | }; 66 | 67 | // JSON type names. 68 | static const char* kJsonBaseTypeName = "!base"; 69 | static const char* kJsonArrayTypeName = "!array"; 70 | static const char* kJsonLambdaTypeName = "!lambda"; 71 | 72 | // XML type names. 73 | static const char* kXmlBaseTypeName = "Base"; 74 | static const char* kXmlArrayTypeName = "Array"; 75 | static const char* kXmlLambdaTypeName = "Lambda"; 76 | 77 | // Map from JSON type tree string names to enum. 78 | static const std::map kMapJsonTypeTreeNodeNamesToEnum = {{kJsonBaseTypeName, TypeTreeNodes::kBaseType}, 79 | {kJsonArrayTypeName, TypeTreeNodes::kArrayType}, 80 | {kJsonLambdaTypeName, TypeTreeNodes::kLambdaType}}; 81 | 82 | // Map from XML type tree string names to enum. 83 | static const std::map kMapXmlTypeTreeNodeNamesToEnum = {{kXmlBaseTypeName, TypeTreeNodes::kBaseType}, 84 | {kXmlArrayTypeName, TypeTreeNodes::kArrayType}, 85 | {kXmlLambdaTypeName, TypeTreeNodes::kLambdaType}}; 86 | } // namespace amdisa 87 | #endif // AMDISA_EXPRESSION_TREE_CONSTANTS_H_ 88 | -------------------------------------------------------------------------------- /source/common/amdisa_structures.cpp: -------------------------------------------------------------------------------- 1 | #include "amdisa_structures.h" 2 | 3 | #include 4 | 5 | namespace amdisa 6 | { 7 | 8 | std::string ToString(const DataType data_type) 9 | { 10 | switch (data_type) 11 | { 12 | case DataType::kInteger: 13 | return "Integer"; 14 | 15 | case DataType::kFloat: 16 | return "Float"; 17 | 18 | case DataType::kBits: 19 | return "Bits"; 20 | 21 | case DataType::kDescriptor: 22 | return "Descriptor"; 23 | 24 | default: 25 | return "Unknown"; 26 | } 27 | } 28 | 29 | std::string ToString(const Signedness signedness) 30 | { 31 | switch (signedness) 32 | { 33 | case Signedness::kDoesNotApply: 34 | return "Does not apply"; 35 | 36 | case Signedness::kUnsigned: 37 | return "Unsigned"; 38 | 39 | case Signedness::kSigned: 40 | return "Signed"; 41 | 42 | case Signedness::kSignedByModifier: 43 | return "Signed by modifier"; 44 | 45 | default: 46 | return "Unknown"; 47 | } 48 | } 49 | 50 | Padding::operator std::string() const noexcept 51 | { 52 | std::stringstream s_stream; 53 | s_stream << "padding bit count : " << bit_count << ' '; 54 | s_stream << "padding value : " << value; 55 | return s_stream.str(); 56 | } 57 | 58 | std::ostream& operator<<(std::ostream& out_stream, const Padding& pad) 59 | { 60 | out_stream << std::string(pad); 61 | return out_stream; 62 | } 63 | 64 | Range::operator std::string() const noexcept 65 | { 66 | std::stringstream s_stream; 67 | s_stream << "-- range-begin--\n"; 68 | 69 | s_stream << "order : " << order << '\n'; 70 | s_stream << "bit count : " << bit_count << '\n'; 71 | s_stream << "bit offset : " << bit_offset << '\n'; 72 | s_stream << "padding : "; 73 | s_stream << padding; 74 | s_stream << '\n'; 75 | 76 | s_stream << "-- range-end --\n"; 77 | return s_stream.str(); 78 | } 79 | std::ostream& operator<<(std::ostream& out_stream, const Range& range) 80 | { 81 | out_stream << std::string(range); 82 | return out_stream; 83 | } 84 | 85 | Field::operator std::string() const noexcept 86 | { 87 | std::stringstream s_stream; 88 | s_stream << "-- field-begin --\n"; 89 | 90 | s_stream << "field name : " << name << '\n'; 91 | s_stream << "description : " << description << '\n'; 92 | s_stream << "conditional : " << (is_conditional ? "yes" : "no") << '\n'; 93 | s_stream << "constant : " << (is_constant ? "yes" : "no") << '\n'; 94 | s_stream << "range count : " << range_count << '\n'; 95 | 96 | s_stream << "-- ranges-begin --\n"; 97 | for (auto& range : ranges) 98 | { 99 | s_stream << range; 100 | s_stream << '\n'; 101 | } 102 | s_stream << "-- ranges-end --\n"; 103 | 104 | s_stream << "signedness : " << amdisa::ToString(signedness) << '\n'; 105 | 106 | s_stream << "-- field-end --\n"; 107 | return s_stream.str(); 108 | } 109 | 110 | std::ostream& operator<<(std::ostream& out_stream, const Field& field) 111 | { 112 | out_stream << std::string(field); 113 | return out_stream; 114 | } 115 | 116 | MicrocodeFormat::operator std::string() const noexcept 117 | { 118 | std::stringstream s_stream; 119 | s_stream << "-- microcode-format-begin --\n"; 120 | 121 | for (auto field : bit_map) 122 | { 123 | s_stream << std::string(field); 124 | s_stream << '\n'; 125 | } 126 | 127 | s_stream << "-- microcode-format-end --\n"; 128 | return s_stream.str(); 129 | } 130 | 131 | std::ostream& operator<<(std::ostream& out_stream, const MicrocodeFormat& uformat) 132 | { 133 | out_stream << std::string(uformat); 134 | return out_stream; 135 | } 136 | 137 | Encoding::operator std::string() const noexcept 138 | { 139 | std::stringstream s_stream; 140 | s_stream << "-- encoding-begin --\n"; 141 | 142 | s_stream << "name : " << name << '\n'; 143 | s_stream << "description : " << description << '\n'; 144 | s_stream << "category : " << category << '\n'; 145 | 146 | s_stream << "encoding identifiers : begin\n"; 147 | s_stream << std::hex; 148 | for (auto encoding_identifier : identifiers) 149 | { 150 | s_stream << encoding_identifier << '\n'; 151 | } 152 | s_stream << "encoding identifiers : end\n"; 153 | 154 | s_stream << "encoding bits : " << bits << '\n'; 155 | s_stream << "encoding mask : " << mask << '\n'; 156 | s_stream << "opcode mask : " << opcode_mask << '\n'; 157 | 158 | s_stream << std::dec; 159 | s_stream << "bit count : " << bit_count << '\n'; 160 | s_stream << "encoding order : " << order << '\n'; 161 | s_stream << "microcode format : " << microcode_format << "\n"; 162 | 163 | s_stream << "-- encoding-end --\n"; 164 | return s_stream.str(); 165 | } 166 | 167 | std::ostream& operator<<(std::ostream& out_stream, const Encoding& encoding) 168 | { 169 | out_stream << std::string(encoding); 170 | return out_stream; 171 | } 172 | 173 | Operand::operator std::string() const noexcept 174 | { 175 | std::stringstream s_stream; 176 | s_stream << "-- operand-begin --\n"; 177 | 178 | s_stream << "field name : " << field_name << '\n'; 179 | s_stream << "data format : " << data_format << '\n'; 180 | s_stream << "operand type : " << type << '\n'; 181 | s_stream << "encoding field name : " << encoding_field_name << '\n'; 182 | s_stream << "order : " << order << '\n'; 183 | s_stream << "input : " << (input ? "yes" : "no") << '\n'; 184 | s_stream << "output : " << (output ? "yes" : "no") << '\n'; 185 | s_stream << "implicit " << (is_implicit ? "yes" : "no") << '\n'; 186 | s_stream << "binary microcode required : " << (is_in_microcode ? "yes" : "no") << '\n'; 187 | 188 | s_stream << "-- operand-end --\n"; 189 | return s_stream.str(); 190 | } 191 | std::ostream& operator<<(std::ostream& out_stream, const Operand& operand) 192 | { 193 | out_stream << std::string(operand); 194 | return out_stream; 195 | } 196 | 197 | InstructionEncoding::operator std::string() const noexcept 198 | { 199 | std::stringstream s_stream; 200 | s_stream << "-- instruction-encoding-begin --\n"; 201 | 202 | s_stream << "name : " << name << '\n'; 203 | s_stream << "opcode : " << opcode << '\n'; 204 | 205 | s_stream << "operands : begin\n"; 206 | for (auto& operand : operands) 207 | { 208 | s_stream << operand; 209 | s_stream << '\n'; 210 | } 211 | s_stream << "operands : end\n"; 212 | 213 | s_stream << "-- instruction-encoding-end --\n"; 214 | return s_stream.str(); 215 | } 216 | 217 | std::ostream& operator<<(std::ostream& out_stream, const InstructionEncoding& encoding) 218 | { 219 | out_stream << std::string(encoding); 220 | return out_stream; 221 | } 222 | 223 | Instruction::operator std::string() const noexcept 224 | { 225 | std::stringstream s_stream; 226 | s_stream << "-- instruction-Dump-begin --\n"; 227 | 228 | s_stream << "name : " << name << '\n'; 229 | s_stream << "description : " << description << '\n'; 230 | 231 | s_stream << "is branch : " << (is_branch ? "yes" : "no") << '\n'; 232 | s_stream << "is immediately executed : " << (is_immediately_executed ? "yes" : "no") << '\n'; 233 | s_stream << "is program terminator : " << (is_program_terminator ? "yes" : "no") << '\n'; 234 | 235 | s_stream << "encodings : begin\n"; 236 | for (const auto& encoding : encodings) 237 | { 238 | s_stream << encoding << '\n'; 239 | } 240 | s_stream << "encodings : end\n"; 241 | 242 | // TODO: semantics 243 | 244 | s_stream << "-- instruction-Dump-end --\n"; 245 | return s_stream.str(); 246 | } 247 | 248 | std::ostream& operator<<(std::ostream& out_stream, const Instruction& instruction) 249 | { 250 | out_stream << std::string(instruction); 251 | return out_stream; 252 | } 253 | 254 | DataAttributes::operator std::string() const noexcept 255 | { 256 | std::stringstream s_stream; 257 | s_stream << "-- data-attributes-begin --\n"; 258 | 259 | s_stream << "bit map : begin\n"; 260 | for (const auto& field : bit_map) 261 | { 262 | s_stream << field << '\n'; 263 | } 264 | s_stream << "bit map : end\n"; 265 | 266 | s_stream << "-- data-attributes-end --\n"; 267 | return s_stream.str(); 268 | } 269 | 270 | std::ostream& operator<<(std::ostream& out_stream, const DataAttributes& attributes) 271 | { 272 | out_stream << std::string(attributes); 273 | return out_stream; 274 | } 275 | 276 | DataFormat::operator std::string() const noexcept 277 | { 278 | std::stringstream s_stream; 279 | s_stream << "-- data-format-begin --"; 280 | 281 | s_stream << "name : " << name << '\n'; 282 | s_stream << "description : " << description << '\n'; 283 | 284 | s_stream << "data type : "; 285 | s_stream << amdisa::ToString(data_type); 286 | s_stream << '\n'; 287 | 288 | s_stream << "bit count : " << bit_count << '\n'; 289 | s_stream << "component count : " << component_count << '\n'; 290 | 291 | s_stream << "data attributes : begin\n"; 292 | for (const auto& attribute : data_attributes) 293 | { 294 | s_stream << attribute << '\n'; 295 | } 296 | s_stream << "data attributes : end\n"; 297 | 298 | s_stream << "-- data-format-end --"; 299 | return s_stream.str(); 300 | } 301 | 302 | std::ostream& operator<<(std::ostream& out_stream, const DataFormat& data_format) 303 | { 304 | out_stream << std::string(data_format); 305 | return out_stream; 306 | } 307 | 308 | PredefinedValue::operator std::string() const noexcept 309 | { 310 | std::stringstream s_stream; 311 | s_stream << "-- operand-predefined-value-begin --\n"; 312 | 313 | s_stream << "name : " << name << '\n'; 314 | s_stream << "description : " << description << '\n'; 315 | s_stream << "value : " << value << '\n'; 316 | 317 | s_stream << "-- operand-predefined-value-begin --\n"; 318 | return s_stream.str(); 319 | } 320 | 321 | std::ostream& operator<<(std::ostream& out_stream, const PredefinedValue& predefined_value) 322 | { 323 | out_stream << std::string(predefined_value); 324 | return out_stream; 325 | } 326 | 327 | OperandType::operator std::string() const noexcept 328 | { 329 | std::stringstream s_stream; 330 | s_stream << "-- operand-type-begin --\n"; 331 | 332 | s_stream << "operand type name : " << name << '\n'; 333 | s_stream << "description : " << description << '\n'; 334 | s_stream << "predefined values : begin\n"; 335 | for (const auto& value : predefined_values) 336 | { 337 | s_stream << value << '\n'; 338 | } 339 | s_stream << "predefined values : end\n"; 340 | 341 | s_stream << "-- operand-type-end --\n"; 342 | return s_stream.str(); 343 | } 344 | 345 | std::ostream& operator<<(std::ostream& out_stream, const OperandType& operand_type) 346 | { 347 | out_stream << std::string(operand_type); 348 | return out_stream; 349 | } 350 | 351 | IsaSpec::operator std::string() const noexcept 352 | { 353 | std::stringstream s_stream; 354 | s_stream << "-- isa-spec-internal-begin --\n"; 355 | 356 | s_stream << "architecture : " << architecture.name; 357 | 358 | s_stream << "encodings : begin\n"; 359 | for (const auto& encoding : encodings) 360 | { 361 | s_stream << encoding << '\n'; 362 | } 363 | s_stream << "encodings : end\n"; 364 | 365 | s_stream << "instructions : begin\n"; 366 | for (const auto& inst : instructions) 367 | { 368 | s_stream << inst << '\n'; 369 | } 370 | s_stream << "instructions : end\n"; 371 | 372 | s_stream << "data formats : begin\n"; 373 | for (const auto& format : data_formats) 374 | { 375 | s_stream << format << '\n'; 376 | } 377 | s_stream << "data formats : end\n"; 378 | 379 | s_stream << "operand types : begin\n"; 380 | for (const auto& type : operand_types) 381 | { 382 | s_stream << type << '\n'; 383 | } 384 | s_stream << "operand types : end\n"; 385 | 386 | s_stream << "-- isa-spec-internal-end --\n"; 387 | return s_stream.str(); 388 | } 389 | 390 | std::ostream& operator<<(std::ostream& out_stream, const IsaSpec& isa_spec) 391 | { 392 | out_stream << std::string(isa_spec); 393 | return out_stream; 394 | } 395 | } // namespace amdisa 396 | -------------------------------------------------------------------------------- /source/common/amdisa_structures.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | #ifndef AMDISA_STRUCTURES_H_ 5 | #define AMDISA_STRUCTURES_H_ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace amdisa 14 | { 15 | // Data types which are referenced by the spec. 16 | enum class DataType 17 | { 18 | // Data type is unknown or was not set. 19 | kUnknown, 20 | 21 | // Integer data type. 22 | kInteger, 23 | 24 | // Float data type. 25 | kFloat, 26 | 27 | // Data type to represent unstructured binary data. 28 | kBits, 29 | 30 | // Data type to represent resource and sampler data. 31 | kDescriptor 32 | }; 33 | 34 | std::string ToString(const DataType data_type); 35 | 36 | // Constant mapping from JSON base_type to data type enum. 37 | static const std::map kStringDataTypeToEnum = {{"unknown", DataType::kUnknown}, 38 | {"integer", DataType::kInteger}, 39 | {"float", DataType::kFloat}, 40 | {"bits", DataType::kBits}, 41 | {"descriptor", DataType::kDescriptor}}; 42 | 43 | // Signedness of the field in the data format. 44 | enum class Signedness 45 | { 46 | kUnknown, 47 | kDoesNotApply, 48 | kUnsigned, 49 | kSigned, 50 | kSignedByModifier 51 | }; 52 | 53 | std::string ToString(const Signedness signedness); 54 | 55 | // Constant mapping from field signedness to strings. 56 | static const std::map kSignednessEnumToString = {{Signedness::kUnknown, "Unknown"}, 57 | {Signedness::kDoesNotApply, "DoesNotApply"}, 58 | {Signedness::kUnsigned, "Unsigned"}, 59 | {Signedness::kSigned, "Signed"}, 60 | {Signedness::kSignedByModifier, "SignedByModifier"}}; 61 | 62 | // Generic expression tree. Saves the structure of the tree. 63 | struct GenericExpressionNode 64 | { 65 | // Expression operator. 66 | std::string expression_operator; 67 | 68 | // Pointers to children nodes. 69 | std::vector> children; 70 | 71 | // Return type node. 72 | bool is_ret_type_node = false; 73 | }; 74 | 75 | // Information describing this spec. 76 | struct SpecMetadata 77 | { 78 | std::string copyright; 79 | std::string sensitivity; 80 | std::string date; 81 | std::string schema_version; 82 | }; 83 | 84 | // Information describing a hardware architecture. 85 | struct Architecture 86 | { 87 | std::string name; 88 | uint32_t id = 0; 89 | }; 90 | 91 | // Padding describes constants values that are inserted into some fields. 92 | struct Padding 93 | { 94 | uint32_t bit_count = 0; 95 | uint32_t value = 0; 96 | 97 | operator std::string() const noexcept; 98 | friend std::ostream& operator<<(std::ostream& os, const Padding& pad); 99 | }; 100 | 101 | // Information describing the range of a Field. The Field can be broken 102 | // down and spread across the microcode. 103 | struct Range 104 | { 105 | uint32_t order = 0; 106 | uint32_t bit_count = 0; 107 | uint32_t bit_offset = 0; 108 | Padding padding; 109 | 110 | operator std::string() const noexcept; 111 | friend std::ostream& operator<<(std::ostream& os, const Range& range); 112 | }; 113 | 114 | // Information describing predefined value. A mapping from value to the string name. 115 | struct PredefinedValue 116 | { 117 | std::string name; 118 | std::string description; 119 | uint32_t value = 0; 120 | 121 | operator std::string() const noexcept; 122 | friend std::ostream& operator<<(std::ostream& os, const PredefinedValue& pv); 123 | }; 124 | 125 | // Information describing a field of a particular section in of the 126 | // microcode format. 127 | struct Field 128 | { 129 | std::string name; 130 | std::string description; 131 | std::string type; 132 | bool is_conditional = false; 133 | bool is_constant = false; 134 | uint32_t range_count = 0; 135 | Signedness signedness = Signedness::kUnknown; 136 | std::vector ranges; 137 | std::vector predefined_values; 138 | 139 | operator std::string() const noexcept; 140 | friend std::ostream& operator<<(std::ostream& os, const Field& field); 141 | }; 142 | 143 | // Constant mapping from data type enum to field name string. 144 | static std::map kDataTypeToFieldName = {{DataType::kDescriptor, "Descriptor"}, 145 | {DataType::kBits, "Bits"}, 146 | {DataType::kInteger, "Integer"}}; 147 | 148 | // Constant mapping from data type enum to field description string. 149 | static const std::map kDataTypeToFieldDescription = {{DataType::kDescriptor, "Descriptor field"}, 150 | {DataType::kBits, "Bits field"}, 151 | {DataType::kInteger, "Integer field"}}; 152 | 153 | // Information describing microcode format, i.e. the structure of the bits 154 | // in a format. 155 | struct MicrocodeFormat 156 | { 157 | std::vector bit_map; 158 | 159 | operator std::string() const noexcept; 160 | friend std::ostream& operator<<(std::ostream& os, const MicrocodeFormat& mf); 161 | }; 162 | 163 | // Encoding conditions. 164 | struct Condition 165 | { 166 | std::string name; 167 | GenericExpressionNode expression; 168 | }; 169 | 170 | // Information describing encodings. 171 | struct Encoding 172 | { 173 | std::vector identifiers; 174 | std::vector conditions; 175 | uint64_t bits = 0; 176 | uint64_t mask = 0; 177 | uint64_t opcode_mask = 0; 178 | uint64_t seg_mask = 0; 179 | uint32_t bit_count = 0; 180 | int32_t order = 0; 181 | std::string name; 182 | std::string description; 183 | std::string category; 184 | MicrocodeFormat microcode_format; 185 | 186 | operator std::string() const noexcept; 187 | friend std::ostream& operator<<(std::ostream& os, const Encoding& enc); 188 | }; 189 | 190 | // Information describing operands of different encodings. 191 | struct Operand 192 | { 193 | std::string field_name; 194 | std::string data_format; 195 | std::string type; 196 | std::string encoding_field_name; 197 | uint32_t order = 0; 198 | uint32_t size = 0; 199 | bool input = false; 200 | bool output = false; 201 | bool is_implicit = false; 202 | bool is_in_microcode = false; 203 | 204 | operator std::string() const noexcept; 205 | friend std::ostream& operator<<(std::ostream& os, const Operand& op); 206 | }; 207 | 208 | // Information describing different instruction encodings. The vector of 209 | // instruction encodings is instantiated in the Instruction struct. 210 | struct InstructionEncoding 211 | { 212 | std::string name; 213 | std::string condition_name; 214 | uint32_t opcode = 0; 215 | std::vector operands; 216 | 217 | operator std::string() const noexcept; 218 | friend std::ostream& operator<<(std::ostream& os, const InstructionEncoding& ie); 219 | }; 220 | 221 | struct InstructionSemantics 222 | { 223 | bool is_defined = false; 224 | GenericExpressionNode semantic_expression; 225 | }; 226 | 227 | // Information describing instructions. 228 | struct Instruction 229 | { 230 | std::string name; 231 | std::vector aliased_names; 232 | std::string description; 233 | std::vector encodings; 234 | InstructionSemantics semantics; 235 | 236 | // True if this instruction is a branch, false otherwise. 237 | bool is_branch = false; 238 | bool is_conditional_branch = false; 239 | bool is_indirect_branch = false; 240 | 241 | // True if this instruction is executed directly by each wave's instruction 242 | // buffer. 243 | bool is_immediately_executed = false; 244 | 245 | // True if this instruction indicates the end of the program and false 246 | // otherwise. 247 | bool is_program_terminator = false; 248 | 249 | std::string functional_group_name; 250 | std::string functional_subgroup_name; 251 | 252 | operator std::string() const noexcept; 253 | friend std::ostream& operator<<(std::ostream& os, const Instruction& ins); 254 | }; 255 | 256 | // Information describing all available functional groups for the instructions 257 | struct FunctionalGroupInfo 258 | { 259 | std::string name; 260 | std::string desc; 261 | }; 262 | 263 | // Information describing all available functional subgroups for the instructions 264 | struct FunctionalSubgroupInfo 265 | { 266 | std::string name; 267 | }; 268 | 269 | // Information describing data attributes. Data attributes are instantiated 270 | // in DataFormat struct 271 | struct DataAttributes 272 | { 273 | uint32_t order = 0; 274 | std::vector bit_map; 275 | 276 | operator std::string() const noexcept; 277 | friend std::ostream& operator<<(std::ostream& os, const DataAttributes& da); 278 | }; 279 | 280 | // Information describing data formats. 281 | struct DataFormat 282 | { 283 | std::string name; 284 | std::string description; 285 | DataType data_type = DataType::kUnknown; 286 | uint32_t bit_count = 0; 287 | uint32_t component_count = 0; 288 | std::vector data_attributes; 289 | 290 | operator std::string() const noexcept; 291 | friend std::ostream& operator<<(std::ostream& os, const DataFormat& df); 292 | }; 293 | 294 | // Information describing operand types. 295 | struct OperandType 296 | { 297 | std::string name; 298 | std::string description; 299 | bool is_partitioned = false; 300 | std::vector subtype_names; 301 | std::vector predefined_values; 302 | MicrocodeFormat microcode_format; 303 | 304 | operator std::string() const noexcept; 305 | friend std::ostream& operator<<(std::ostream& os, const OperandType& ot); 306 | }; 307 | 308 | // Information related to translation of promoted instructions. 309 | struct EncodingTranslation 310 | { 311 | uint64_t actual_op_start = 0; 312 | uint64_t native_op_start = 0; 313 | uint64_t num_ops = 0; 314 | std::string actual_encoding; 315 | std::string native_encoding; 316 | }; 317 | 318 | // Structure for accessing the ISA spec data. 319 | struct IsaSpec 320 | { 321 | // Metadata describing the spec. 322 | SpecMetadata info; 323 | 324 | // The architecture which is described by this spec. 325 | Architecture architecture; 326 | 327 | // Container for all the ISA encodings. 328 | std::vector encodings; 329 | 330 | // Container for all the ISA instructions. 331 | std::vector instructions; 332 | 333 | // Container for all data formats. 334 | std::vector data_formats; 335 | 336 | // Container for all operand types. 337 | std::vector operand_types; 338 | 339 | // Container for functional groups 340 | std::vector functional_group_info; 341 | 342 | // Container for functional subgroups 343 | std::vector functional_subgroup_info; 344 | 345 | operator std::string() const noexcept; 346 | friend std::ostream& operator<<(std::ostream& os, const IsaSpec& is); 347 | }; 348 | }; // namespace amdisa 349 | #endif // AMDISA_STRUCTURES_H_ 350 | -------------------------------------------------------------------------------- /source/common/amdisa_utility.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | #include "amdisa_utility.h" 5 | 6 | // C++ libraries. 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // Local libraries. 13 | #include "amdisa_structures.h" 14 | 15 | namespace amdisa 16 | { 17 | // Warning string constants. 18 | static const char* kStringWarningCouldNotConvertStrToUnsigned = "Warning: could not convert string to integer: "; 19 | 20 | bool AmdIsaUtility::GetRange(const Field& field, Range& range) 21 | { 22 | bool is_range_retrieved = false; 23 | if (!field.ranges.empty()) 24 | { 25 | range = field.ranges[0]; 26 | is_range_retrieved = true; 27 | } 28 | 29 | return is_range_retrieved; 30 | } 31 | 32 | void AmdIsaUtility::BitMapToString(const MicrocodeFormat& microcode_format, const std::vector& machine_code, std::string& string_bitmap) 33 | { 34 | std::stringstream ret; 35 | for (const auto& field : microcode_format.bit_map) 36 | { 37 | Range range; 38 | if (GetRange(field, range)) 39 | { 40 | uint32_t bit_offset = range.bit_offset; 41 | uint32_t bit_count = range.bit_count; 42 | uint32_t upper = bit_offset + bit_count - 1; 43 | uint32_t lower = bit_offset; 44 | uint32_t dword_index = bit_offset / 32; 45 | 46 | ret << " " << std::left << std::setw(13) << field.name << "[" << std::right << std::dec << std::setw(2) << upper << ":" << std::setw(2) 47 | << lower << "]"; 48 | 49 | uint32_t dword = 0; 50 | if (dword_index < machine_code.size()) 51 | { 52 | dword = machine_code[dword_index]; 53 | } 54 | 55 | uint64_t field_val = (dword >> (bit_offset - 32 * dword_index)) & ((1 << bit_count) - 1); 56 | ret << " = " << std::hex << field_val; 57 | ret << std::endl; 58 | } 59 | } 60 | 61 | string_bitmap = ret.str(); 62 | } 63 | 64 | std::string AmdIsaUtility::ToUpper(const std::string& str) 65 | { 66 | std::string ustr = str; 67 | std::transform(ustr.begin(), ustr.end(), ustr.begin(), [](const char& c) { return std::toupper(c); }); 68 | return ustr; 69 | } 70 | 71 | std::string AmdIsaUtility::ToLower(const std::string& str) 72 | { 73 | std::string lstr = str; 74 | std::transform(lstr.begin(), lstr.end(), lstr.begin(), [](const char& c) { return std::tolower(c); }); 75 | return lstr; 76 | } 77 | 78 | std::string AmdIsaUtility::Strip(const std::string& str) 79 | { 80 | std::string stripped_str; 81 | if (str.length() > 0) 82 | { 83 | int32_t pos_start = 0; 84 | size_t pos_end = str.length() - 1; 85 | 86 | // Skip leading whitespaces and special chars. 87 | auto should_skip = [](const char& c) { return c == ' ' || c == '\n' || c == '\r' || c == '\t'; }; 88 | while (pos_start < str.length() && should_skip(str[pos_start])) 89 | { 90 | ++pos_start; 91 | } 92 | 93 | // Skip trailing whitespaces and special chars. 94 | while (pos_end - pos_start >= 0 && should_skip(str[pos_end])) 95 | { 96 | --pos_end; 97 | } 98 | 99 | // Get the middle. 100 | for (size_t i = pos_start; i <= pos_end && pos_end != std::string::npos; i++) 101 | { 102 | stripped_str += str[i]; 103 | } 104 | } 105 | 106 | return stripped_str; 107 | } 108 | 109 | uint64_t AmdIsaUtility::StringToUnsignedInt(const std::string& str) 110 | { 111 | uint64_t result = 0; 112 | try 113 | { 114 | result = std::stoull(str); 115 | } 116 | catch (std::exception& err) 117 | { 118 | std::cout << kStringWarningCouldNotConvertStrToUnsigned << str << ". Exception: " << err.what() << std::endl; 119 | } 120 | return result; 121 | } 122 | } // namespace amdisa 123 | -------------------------------------------------------------------------------- /source/common/amdisa_utility.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | #ifndef AMDISA_UTILITY_H_ 5 | #define AMDISA_UTILITY_H_ 6 | 7 | // C++ libraries. 8 | #include 9 | #include 10 | #include 11 | 12 | namespace amdisa 13 | { 14 | // Forward declarations. 15 | struct MicrocodeFormat; 16 | struct Range; 17 | struct Field; 18 | 19 | class AmdIsaUtility 20 | { 21 | public: 22 | static void BitMapToString(const MicrocodeFormat& microcode_format, const std::vector& machine_code, std::string& string_bitmap); 23 | static std::string ToUpper(const std::string& str); 24 | static std::string ToLower(const std::string& str); 25 | static std::string Strip(const std::string& str); 26 | static uint64_t StringToUnsignedInt(const std::string& str_num); 27 | static bool GetRange(const Field& field, Range& range); 28 | }; 29 | } // namespace amdisa 30 | #endif // AMDISA_UTILITY_H_ 31 | -------------------------------------------------------------------------------- /source/common/amdisa_xml_element_consts.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | #ifndef AMDISA_XML_ELEMENT_CONSTS_H_ 5 | #define AMDISA_XML_ELEMENT_CONSTS_H_ 6 | 7 | namespace amdisa 8 | { 9 | // Names of XML elements. 10 | // Top elements. 11 | static const char* kElementSpec = "Spec"; 12 | static const char* kElementDocument = "Document"; 13 | static const char* kElementCopyright = "Copyright"; 14 | static const char* kElementSensitivity = "Sensitivity"; 15 | static const char* kElementDate = "ReleaseDate"; 16 | static const char* kElementIsa = "ISA"; 17 | static const char* kElementSchemaVersion = "SchemaVersion"; 18 | 19 | // Architecture specific elements. 20 | static const char* kElementArchitecture = "Architecture"; 21 | static const char* kElementArchitectureName = "ArchitectureName"; 22 | static const char* kElementArchitectureId = "ArchitectureId"; 23 | 24 | // Encoding specific elements. 25 | static const char* kElementEncodings = "Encodings"; 26 | static const char* kElementEncoding = "Encoding"; 27 | static const char* kElementEncodingIdentifiers = "EncodingIdentifiers"; 28 | static const char* kElementEncodingIdentifier = "EncodingIdentifier"; 29 | static const char* kElementEncodingIdentifierMask = "EncodingIdentifierMask"; 30 | static const char* kElementEncodingName = "EncodingName"; 31 | static const char* kElementEncodingDescription = "EncodingDescription"; 32 | static const char* kElementEncodingCategory = "EncodingCategory"; 33 | static const char* kElementMicrocodeFormat = "MicrocodeFormat"; 34 | static const char* kElementEncodingFields = "EncodingFields"; 35 | static const char* kElementEncodingConditions = "EncodingConditions"; 36 | static const char* kElementEncodingCondition = "EncodingCondition"; 37 | static const char* kElementConditionName = "ConditionName"; 38 | static const char* kElementConditionExpression = "CondtionExpression"; 39 | 40 | // Field specific elements. 41 | static const char* kElementField = "Field"; 42 | static const char* kElementFieldName = "FieldName"; 43 | static const char* kElementFieldPredefinedValues = "FieldPredefinedValues"; 44 | 45 | // Bit specific elements. 46 | static const char* kElementBitCount = "BitCount"; 47 | static const char* kElementBitMap = "BitMap"; 48 | static const char* kElementBitLayout = "BitLayout"; 49 | static const char* kElementBitOffset = "BitOffset"; 50 | 51 | // Expression specific elements. 52 | static const char* kElementExpression = "Expression"; 53 | static const char* kElementExpressionOperator = "Operator"; 54 | static const char* kElementExpressionValue = "Value"; 55 | static const char* kElementExpressionLabel = "Label"; 56 | static const char* kElementExpressionComment = "Comment"; 57 | static const char* kElementSubexpressions = "Subexpressions"; 58 | static const char* kElementExpressionValueTypes = "ValueTypes"; 59 | static const char* kElementExpressionValueType = "ValueType"; 60 | static const char* kElementExpressionBaseType = "BaseType"; 61 | static const char* kElementExpressionArrayType = "ArrayType"; 62 | static const char* kElementExpressionTypeSize = "Size"; 63 | static const char* kElementExpressionArraySize = "ArraySize"; 64 | static const char* kElementExpressionReturnType = "ReturnType"; 65 | 66 | // Instruction specific elements. 67 | static const char* kElementInstructions = "Instructions"; 68 | static const char* kElementShaderInstructions = "ShaderInstructions"; 69 | static const char* kElementInstruction = "Instruction"; 70 | static const char* kElementInstructionName = "InstructionName"; 71 | static const char* kElementAliasedInstructionName = "AliasedInstructionNames"; 72 | static const char* kElementInstructionDescription = "InstructionDescription"; 73 | static const char* kElementInstructionOrder = "InstructionOrder"; 74 | static const char* kElementInstructionSemantics = "InstructionSemantics"; 75 | static const char* kElementInstructionEncodings = "InstructionEncodings"; 76 | static const char* kElementInstructionEncoding = "InstructionEncoding"; 77 | static const char* kElementInstructionBranchInfo = "InstructionBranchInfo"; 78 | static const char* kElementInstructionBranchOffset = "InstructionBranchOffset"; 79 | static const char* kElementInstructionBranchTargetPC = "InstructionBranchTargetPC"; 80 | static const char* kElementInstructionBranchTargetLabel = "InstructionBranchTargetLabel"; 81 | static const char* kElementInstructionBranchTargetIndex = "InstructionBranchTargetIndex"; 82 | static const char* kElementInstructionFlags = "InstructionFlags"; 83 | static const char* kElementExecutionUnit = "ExecutionUnit"; 84 | static const char* kElementFlagIsBranch = "IsBranch"; 85 | static const char* kElementFlagIsConditionalBranch = "IsConditionalBranch"; 86 | static const char* kElementFlagIsIndirectBranch = "IsIndirectBranch"; 87 | static const char* kElementFlagIsProgramTerminator = "IsProgramTerminator"; 88 | static const char* kElementFlagIsImmediatelyExecuted = "IsImmediatelyExecuted"; 89 | 90 | // Data format specific elements. 91 | static const char* kElementDataFormats = "DataFormats"; 92 | static const char* kElementDataFormat = "DataFormat"; 93 | static const char* kElementDataFormatName = "DataFormatName"; 94 | static const char* kElementDataType = "DataType"; 95 | static const char* kElementDataAttributes = "DataAttributes"; 96 | 97 | // Operand type specific elements. 98 | static const char* kElementOperands = "Operands"; 99 | static const char* kElementOperand = "Operand"; 100 | static const char* kElementOperandTypes = "OperandTypes"; 101 | static const char* kElementOperandSubtypes = "Subtypes"; 102 | static const char* kElementOperandSubtype = "Subtype"; 103 | static const char* kElementOperandSize = "OperandSize"; 104 | static const char* kElementOperandType = "OperandType"; 105 | static const char* kElementOperandTypeName = "OperandTypeName"; 106 | static const char* kElementOperandPredefinedValues = "OperandPredefinedValues"; 107 | static const char* kElementOperandModifier = "OperandModifier"; 108 | static const char* kElementOperandModifiers = "OperandModifiers"; 109 | static const char* kElementPredefinedValue = "PredefinedValue"; 110 | 111 | // Padding specific elements. 112 | static const char* kElementPadding = "Padding"; 113 | 114 | // Generic elements. 115 | static const char* kElementDescription = "Description"; 116 | static const char* kElementConstant = "Constant"; 117 | static const char* kElementRange = "Range"; 118 | static const char* kElementCondition = "Condition"; 119 | static const char* kElementOpcode = "Opcode"; 120 | static const char* kElementIsPartitioned = "IsPartitioned"; 121 | static const char* kElementValue = "Value"; 122 | static const char* kElementName = "Name"; 123 | static const char* kElementComponentCount = "ComponentCount"; 124 | static const char* kElementBinaryRepresentation = "BinaryRepresentation"; 125 | static const char* kElementIsInstructionDecoded = "IsInstructionDecoded"; 126 | static const char* kElementSubgroup = "Subgroup"; 127 | static const char* kElementFunctionalGroup = "FunctionalGroup"; 128 | static const char* kElementFunctionalGroups = "FunctionalGroups"; 129 | static const char* kElementFunctionalSubgroups = "FunctionalSubgroups"; 130 | static const char* kElementFunctionalSubgroup = "FunctionalSubgroup"; 131 | 132 | // Attributes of XML elements. 133 | static const char* kAttributePublishDate = "PublishDate"; 134 | static const char* kAttributeRadix = "Radix"; 135 | static const char* kAttributeIsConditional = "IsConditional"; 136 | static const char* kAttributeRangeCount = "RangeCount"; 137 | static const char* kAttributeOrder = "Order"; 138 | static const char* kAttributeOperator = "Operator"; 139 | static const char* kAttributeInput = "Input"; 140 | static const char* kAttributeOutput = "Output"; 141 | static const char* kAttributeIsImplicit = "IsImplicit"; 142 | static const char* kAttributeIsBinaryMicrocodeRequired = "IsBinaryMicrocodeRequired"; 143 | static const char* kAttributeSignedness = "Signedness"; 144 | static const char* kAttributeIsPartitioned = "IsPartitioned"; 145 | static const char* kAttributeType = "Type"; 146 | static const char* kAttributeTypeName = "Name"; 147 | } // namespace amdisa 148 | #endif // AMDISA_XML_ELEMENT_CONSTS_H_ 149 | -------------------------------------------------------------------------------- /source/common/isa_xml_reader.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | #ifndef ISA_XML_READER_H_ 5 | #define ISA_XML_READER_H_ 6 | 7 | // C++ libraries. 8 | #include 9 | 10 | namespace amdisa 11 | { 12 | // Forward declarations. 13 | struct IsaSpec; 14 | 15 | class IsaXmlReader 16 | { 17 | public: 18 | static bool ReadSpec(const std::string& path_to_input_xml, IsaSpec& spec_data, std::string& err_message); 19 | 20 | // Explicitly remove the constructors and assignment operators. 21 | IsaXmlReader() = delete; 22 | IsaXmlReader(const IsaXmlReader&) = delete; 23 | IsaXmlReader& operator=(const IsaXmlReader&) = delete; 24 | }; 25 | } // namespace amdisa 26 | #endif // ISA_XML_READER_H_ 27 | -------------------------------------------------------------------------------- /source/common/logger.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | #include "logger.h" 5 | 6 | namespace amdisa 7 | { 8 | Logger::~Logger() 9 | { 10 | if (output_file_.is_open()) 11 | { 12 | output_file_.close(); 13 | } 14 | } 15 | 16 | bool Logger::Init(const std::string& path, const std::string& file_name) 17 | { 18 | if (!output_file_.is_open()) 19 | { 20 | std::string full_path; 21 | if (path.empty()) 22 | { 23 | full_path = file_name; 24 | } 25 | else 26 | { 27 | full_path = path + "/" + file_name; 28 | } 29 | 30 | output_file_.open(full_path); 31 | } 32 | 33 | return output_file_.is_open(); 34 | } 35 | 36 | void Logger::Log(const std::string& message, uint32_t indent) 37 | { 38 | std::string indentation; 39 | while (indent > 0) 40 | { 41 | indentation += " "; 42 | --indent; 43 | } 44 | output_file_ << indentation << message << std::endl; 45 | } 46 | } // namespace amdisa -------------------------------------------------------------------------------- /source/common/logger.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | #ifndef LOGGER_H_ 5 | #define LOGGER_H_ 6 | 7 | // C++ libraries. 8 | #include 9 | #include 10 | 11 | namespace amdisa 12 | { 13 | class Logger 14 | { 15 | public: 16 | void Log(const std::string& message, uint32_t indent = 0); 17 | bool Init(const std::string& path, const std::string& file_name); 18 | Logger() = default; 19 | ~Logger(); 20 | 21 | private: 22 | std::ofstream output_file_; 23 | }; 24 | } // namespace amdisa 25 | #endif // LOGGER_H_ 26 | -------------------------------------------------------------------------------- /source/examples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 2 | cmake_minimum_required(VERSION 3.0) 3 | 4 | # Setting project directories. 5 | set (SRC_DIR ../../source) 6 | set (INC_DIR ../../include) 7 | 8 | # Redirect to single build output location 9 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output) 10 | 11 | # Adding target for BasicDecoder example 12 | add_executable(basic_decoder ./basic_decoder.cpp) 13 | 14 | target_include_directories(basic_decoder PRIVATE 15 | ${INC_DIR} 16 | ) 17 | target_link_libraries(basic_decoder PRIVATE 18 | isa_decoder 19 | ) 20 | 21 | # Adding target for Multi-Architecture support example. 22 | add_executable(multiarch_decoder ./multi_arch_decoder.cpp) 23 | 24 | target_include_directories(multiarch_decoder PRIVATE 25 | ${INC_DIR} 26 | ) 27 | target_link_libraries(multiarch_decoder PRIVATE 28 | isa_decoder 29 | ) 30 | 31 | 32 | # Adding target for basic_explorer 33 | add_executable(basic_explorer ./basic_explorer.cpp) 34 | 35 | target_include_directories(basic_explorer PRIVATE 36 | ${INC_DIR} 37 | ) 38 | target_link_libraries(basic_explorer PRIVATE 39 | isa_explorer 40 | ) 41 | 42 | # Group these projects under an Examples folder. 43 | set_target_properties(multiarch_decoder basic_decoder basic_explorer PROPERTIES FOLDER "examples") 44 | -------------------------------------------------------------------------------- /source/examples/basic_decoder.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | // IsaDecoderExamples.cpp: Demonstrates the decoding of an example single 5 | // instruction's binary representation using IsaDecoder - DecodeInstruction(). 6 | // Required Argument for the program: Valid ISA Spec XML file path. 7 | 8 | // C++. 9 | #include 10 | #include 11 | #include 12 | 13 | // ISA Spec API. 14 | #include "amdisa/isa_decoder.h" 15 | 16 | // Constants. 17 | // Error constant string. 18 | static const char* kStrErrorInvalidArgument = "Error: Requires one program argument."; 19 | static const char* kStrErrorSpecNotInitialized = "Error: Spec not initialized. "; 20 | static const char* kStrErrorDecodeFail = "Error: Instruction failed to decode. "; 21 | 22 | // Info constant string. 23 | static const char* kStrInfoInitializingSpec = "Info: Initializing AMD ISA Spec from "; 24 | static const char* kStrInfoSpecInitialized = "Info: ISA Spec is now initialized."; 25 | static const char* kStrInfoDecodingInstruction = "Info: Decoding Instruction "; 26 | static const char* kStrInfoDecodeSuccess = "Info: Instruction decoded successfully."; 27 | 28 | int main(int argc, char* argv[]) 29 | { 30 | // Decoding API example. 31 | amdisa::IsaDecoder spec_api_example; 32 | 33 | // bool flags to check for failures. 34 | bool is_error = false; 35 | bool is_success = false; 36 | 37 | // Check for valid Input Argument. 38 | if (argc != 2) 39 | { 40 | std::cerr << kStrErrorInvalidArgument << std::endl; 41 | is_error = true; 42 | } 43 | 44 | std::string error_msg; 45 | 46 | // Initialize the API with a spec. 47 | if (!is_error) 48 | { 49 | const std::string kPathToSpec = argv[1]; 50 | std::cout << kStrInfoInitializingSpec << kPathToSpec << std::endl; 51 | is_success = spec_api_example.Initialize(kPathToSpec, error_msg); 52 | 53 | // Print API version and XML compatibility messages. 54 | std::cout << "API version: " << spec_api_example.GetVersion() << std::endl; 55 | if (error_msg.length() > 0) 56 | { 57 | std::cout << error_msg << std::endl; 58 | } 59 | 60 | // Check if the ISA spec is initialized. 61 | if (!is_success) 62 | { 63 | std::cerr << kStrErrorSpecNotInitialized << error_msg << std::endl; 64 | is_error = true; 65 | } 66 | else 67 | { 68 | std::cout << kStrInfoSpecInitialized << std::endl; 69 | } 70 | } 71 | 72 | if (!is_error) 73 | { 74 | // Prepare the input sample instruction's binary representation. 75 | const std::string kStrSampleInstructionBinary = "8BEA7E6A"; 76 | std::cout << kStrInfoDecodingInstruction << kStrSampleInstructionBinary << std::endl; 77 | std::stringstream kIsaInstructionStream; 78 | kIsaInstructionStream << kStrSampleInstructionBinary; 79 | uint64_t instruction_binary = 0; 80 | kIsaInstructionStream >> std::hex >> instruction_binary; 81 | 82 | // Decode an instruction. 83 | amdisa::InstructionInfoBundle instruction_info; 84 | is_success = spec_api_example.DecodeInstruction(instruction_binary, instruction_info, error_msg); 85 | 86 | if (!is_success) 87 | { 88 | std::cerr << kStrErrorDecodeFail << error_msg << std::endl; 89 | is_error = true; 90 | } 91 | else 92 | { 93 | std::cout << kStrInfoDecodeSuccess << std::endl; 94 | 95 | // Display decoded instruction's information from the instruction_info 96 | // bundle (InstructionInfo). 97 | for (const auto& inst : instruction_info.bundle) 98 | { 99 | std::cout << "Instruction Name: " << inst.instruction_name << std::endl; 100 | std::cout << "Instruction Description: " << inst.instruction_description << std::endl; 101 | std::cout << "Encoding Name: " << inst.encoding_name << std::endl; 102 | std::cout << "Encoding Description: " << inst.encoding_description << std::endl; 103 | std::cout << "Functional Group: " << amdisa::kFunctionalGroupName[static_cast(inst.functional_group_subgroup_info.IsaFunctionalGroup)] 104 | << std::endl; 105 | std::cout << "Functional Subgroup: " 106 | << amdisa::kFunctionalSubgroupName[static_cast(inst.functional_group_subgroup_info.IsaFunctionalSubgroup)] << std::endl; 107 | std::cout << "Functional Group Description: " << inst.functional_group_subgroup_info.description << std::endl; 108 | // Similarly, the following information about the instruction can be 109 | // fetched: 110 | // 1. encoding: 111 | // encoding_fields - field_name, field_value, bit_count, bit_offset 112 | // encoding_layout 113 | // 2. operands: 114 | // instruction_operands - operand_name, operand_size, is_input, 115 | // is_output 116 | // 3. modifiers: 117 | // operand_modifiers - modifier_name, value 118 | // 4. semantics: 119 | // instruction_semantic_info - is_program_terminator, 120 | // is_immediately_executed, 121 | // branch_info (is_branch, 122 | // is_conditional, is_indirect, 123 | // branch_offset, branch_target_PC, 124 | // branch_target_index) 125 | } 126 | } 127 | 128 | // Print debug log messages if present. 129 | for (const std::string& message : spec_api_example.GetDebugLog()) 130 | { 131 | std::cout << message << std::endl; 132 | } 133 | } 134 | 135 | return 0; 136 | } 137 | -------------------------------------------------------------------------------- /source/examples/basic_explorer.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | #include "amdisa/isa_explorer.h" 6 | 7 | // Constants. 8 | // Error constant string. 9 | static const char* kStrErrorInvalidArgument = "Error: Requires XML specification path."; 10 | 11 | static void print_instruction(const amdisa::explorer::Instruction& instruction) 12 | { 13 | std::cout << "Name: " << instruction.Name() << std::endl; 14 | std::cout << "\tDescription: " << instruction.Description() << std::endl; 15 | std::cout << "\tIsBranch ?: " << instruction.IsBranch() << std::endl; 16 | std::cout << "\tIsConditionalBranch ?: " << instruction.IsConditionalBranch() << std::endl; 17 | std::cout << "\tIsIndirectBranch ?: " << instruction.IsIndirectBranch() << std::endl; 18 | std::cout << "\tFunctionalGroup: " << instruction.FuncGroup()->Name() << std::endl; 19 | std::cout << "\t\t Description: " << instruction.FuncGroup()->Description() << std::endl << std::endl; 20 | std::cout << "\tFunctionalSubgroup: " << instruction.FuncSubgroup()->Name() << std::endl; 21 | } 22 | 23 | int main(int argc, char** argv) 24 | { 25 | // Check for valid input argument. 26 | if (argc != 2) 27 | { 28 | std::cerr << kStrErrorInvalidArgument << std::endl; 29 | return -1; 30 | } 31 | 32 | amdisa::explorer::Spec explorer; 33 | 34 | // Check API version. 35 | std::cout << "IsaExplorer version: " << explorer.GetApiVersion() << std::endl; 36 | 37 | const std::string kPathToSpec = argv[1]; 38 | std::string err_message; 39 | bool is_init = explorer.Init(kPathToSpec, err_message); 40 | 41 | // Check for successful spec initialization. 42 | if (!is_init) 43 | { 44 | std::cerr << err_message << std::endl; 45 | return -1; 46 | } 47 | 48 | // Lookup an instruction by name. 49 | auto v_mov_b32 = explorer.GetInstructions().at("V_MOV_B32"); 50 | print_instruction(v_mov_b32); 51 | 52 | // Choose a random instruction and print it. 53 | std::random_device rd; 54 | std::mt19937 gen(rd()); 55 | std::uniform_int_distribution dist(0, explorer.GetInstructions().size() - 1); 56 | 57 | auto it = explorer.GetInstructions().begin(); 58 | std::advance(it, dist(gen)); 59 | print_instruction(it->second); 60 | 61 | return 0; 62 | } 63 | -------------------------------------------------------------------------------- /source/examples/multi_arch_decoder.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | // multi_arch_decode.cpp: Demonstrates the decoding of instructions 5 | // by loading several architectures at once. 6 | // The following code snippet demonstrates how to use amdisa::DecodeManager. 7 | // The amdisa::DecodeManager can be helpful in case that you need to decode ISA for multiple different AMD GPU architectures 8 | // in a single session, as it allows loading multiple specification files at once. It is merely a convenience interface which 9 | // does not add any additional functionality. Everything can be done using amdisa::IsaDecoder directly, it will just require more code. 10 | // The three specification files that we will decode. 11 | 12 | // C++. 13 | #include 14 | #include 15 | #include 16 | 17 | // ISA Spec API. 18 | #include "amdisa/isa_decoder.h" 19 | 20 | // Constants. 21 | // Error constant string. 22 | static const char* kStrErrorInvalidArgument = "Error: Requires at least one program argument."; 23 | static const char* kStrErrorSpecNotInitialized = "Error: Spec not initialized.\n"; 24 | static const char* kStrErrorDecodeFail = "Error: Instruction failed to decode. "; 25 | static const char* kStrErrorRetrieveFail = "Error: Manager failed to retrieve the decoder."; 26 | 27 | // Info constant string. 28 | static const char* kStrInfoInitializingManager = "Info: Initializing DecodeManager from the following specs: "; 29 | static const char* kStrInfoManagerInitialized = "Info: DecodeManager is now initialized."; 30 | static const char* kStrInfoRetrieveDecoder = "Info: Retrieving the decoder."; 31 | static const char* kStrInfoDecodingInstruction = "Info: Decoding Instruction "; 32 | static const char* kStrInfoDecodeSuccess = "Info: Instruction decoded successfully."; 33 | 34 | int main(int argc, char* argv[]) 35 | { 36 | // Decoding API example. 37 | amdisa::DecodeManager decode_manager; 38 | 39 | // bool flags to check for failures. 40 | bool is_error = false; 41 | bool is_success = false; 42 | 43 | // Check for valid Input Argument. 44 | if (argc < 2) 45 | { 46 | std::cerr << kStrErrorInvalidArgument << std::endl; 47 | is_error = true; 48 | } 49 | 50 | std::string error_msg; 51 | 52 | // Initialize the API with a spec. 53 | if (!is_error) 54 | { 55 | // Get paths from CLI arguments. 56 | std::cout << kStrInfoInitializingManager << std::endl; 57 | std::vector xml_spec_paths; 58 | for (uint32_t i = 1; i < argc; i++) 59 | { 60 | xml_spec_paths.push_back(argv[i]); 61 | std::cout << " - " << argv[i] << std::endl; 62 | } 63 | 64 | // Initialize the DecodeManager object with all paths. 65 | is_success = decode_manager.Initialize(xml_spec_paths, error_msg); 66 | 67 | // Check if the ISA spec is initialized. 68 | if (is_success) 69 | { 70 | std::cout << kStrInfoManagerInitialized << std::endl; 71 | } 72 | else 73 | { 74 | std::cerr << kStrErrorSpecNotInitialized << error_msg << std::endl; 75 | is_error = true; 76 | } 77 | } 78 | 79 | if (!is_error) 80 | { 81 | // Prepare the input sample instruction's binary representation. 82 | const std::string kStrSampleInstructionBinary = "8BEA7E6A"; 83 | std::cout << kStrInfoDecodingInstruction << kStrSampleInstructionBinary << std::endl; 84 | std::stringstream kIsaInstructionStream; 85 | kIsaInstructionStream << kStrSampleInstructionBinary; 86 | uint64_t instruction_binary = 0; 87 | kIsaInstructionStream >> std::hex >> instruction_binary; 88 | 89 | // Retrieve decoder. 90 | std::cout << kStrInfoRetrieveDecoder << std::endl; 91 | std::shared_ptr rdna3_decoder = decode_manager.GetDecoder(amdisa::GpuArchitecture::kRdna3); 92 | is_success = rdna3_decoder != nullptr; 93 | 94 | // Decode an instruction. 95 | amdisa::InstructionInfoBundle instruction_info; 96 | if (is_success) 97 | { 98 | is_success = rdna3_decoder->DecodeInstruction(instruction_binary, instruction_info, error_msg); 99 | } 100 | else 101 | { 102 | std::cerr << kStrErrorRetrieveFail << std::endl; 103 | } 104 | 105 | if (is_success) 106 | { 107 | std::cout << kStrInfoDecodeSuccess << std::endl; 108 | 109 | // Display decoded instruction's information from the instruction_info 110 | // bundle (InstructionInfo). 111 | for (const auto& inst : instruction_info.bundle) 112 | { 113 | std::cout << "Instruction Name: " << inst.instruction_name << std::endl; 114 | std::cout << "Instruction Description: " << inst.instruction_description << std::endl; 115 | std::cout << "Encoding Name: " << inst.encoding_name << std::endl; 116 | std::cout << "Encoding Description: " << inst.encoding_description << std::endl; 117 | std::cout << "Functional Group: " << amdisa::kFunctionalGroupName[static_cast(inst.functional_group_subgroup_info.IsaFunctionalGroup)] 118 | << std::endl; 119 | std::cout << "Functional Subgroup: " 120 | << amdisa::kFunctionalSubgroupName[static_cast(inst.functional_group_subgroup_info.IsaFunctionalSubgroup)] << std::endl; 121 | std::cout << "Functional Group Description: " << inst.functional_group_subgroup_info.description << std::endl; 122 | // Similarly, the following information about the instruction can be 123 | // fetched: 124 | // 1. encoding: 125 | // encoding_fields - field_name, field_value, bit_count, bit_offset 126 | // encoding_layout 127 | // 2. operands: 128 | // instruction_operands - operand_name, operand_size, is_input, 129 | // is_output 130 | // 3. modifiers: 131 | // operand_modifiers - modifier_name, value 132 | // 4. semantics: 133 | // instruction_semantic_info - is_program_terminator, 134 | // is_immediately_executed, 135 | // branch_info (is_branch, 136 | // is_conditional, is_indirect, 137 | // branch_offset, branch_target_PC, 138 | // branch_target_index) 139 | } 140 | } 141 | else 142 | { 143 | std::cerr << kStrErrorDecodeFail << error_msg << std::endl; 144 | is_error = true; 145 | } 146 | } 147 | 148 | return 0; 149 | } 150 | -------------------------------------------------------------------------------- /source/isa_decoder/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 2 | cmake_minimum_required(VERSION 3.0) 3 | 4 | # Setting project directories. 5 | set (SRC_DIR ../../source) 6 | set (INC_DIR ../../include) 7 | set (THIRD_PARTY_DIR ../third_party) 8 | 9 | # Control the path of tinyxml2. 10 | set (TINYXML_DIR ${THIRD_PARTY_DIR}/tinyxml2) 11 | if (TINYXML_SRC_PATH) 12 | message("-- IsaDecoder: Overwritting default tinyxml2 source files with ${TINYXML_SRC_PATH}") 13 | set (TINYXML_DIR ${TINYXML_SRC_PATH}) 14 | endif() 15 | 16 | # Redirect to single build output location 17 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output) 18 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output) 19 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output) 20 | 21 | # Local target: IsaDecoder. 22 | # Setting all header files for this project. 23 | set (ALL_H 24 | # Top interface header. 25 | ${INC_DIR}/amdisa/isa_decoder.h 26 | ${INC_DIR}/amdisa/api_version.h 27 | 28 | # Local library headers. 29 | ${SRC_DIR}/common/amdisa_expression_tree_consts.h 30 | ${SRC_DIR}/common/amdisa_structures.h 31 | ${SRC_DIR}/common/amdisa_xml_element_consts.h 32 | ${SRC_DIR}/common/amdisa_utility.h 33 | ${SRC_DIR}/common/isa_xml_reader.h 34 | 35 | # Third party library headers. 36 | ${TINYXML_DIR}/tinyxml2.h 37 | ) 38 | 39 | # Setting all source files for this project. 40 | set (ALL_CPP 41 | # Top interface source file. 42 | ./isa_decoder.cpp 43 | ./encoding_condition_handler.hpp 44 | 45 | # Local library source files. 46 | ${SRC_DIR}/common/amdisa_utility.cpp 47 | ${SRC_DIR}/common/amdisa_structures.cpp 48 | ${SRC_DIR}/common/isa_xml_reader.cpp 49 | 50 | # Third party source files. 51 | ${TINYXML_DIR}/tinyxml2.cpp 52 | ) 53 | 54 | # Adding target. 55 | # Static Library 56 | add_library(isa_decoder STATIC ${ALL_CPP}) 57 | target_include_directories(isa_decoder PRIVATE 58 | ${SRC_DIR}/common 59 | ${TINYXML_DIR} 60 | PUBLIC 61 | ${INC_DIR} 62 | ) 63 | 64 | # Dynamic Library 65 | add_library(isa_decoder_dynamic SHARED ${ALL_CPP}) 66 | target_include_directories(isa_decoder_dynamic PRIVATE 67 | ${SRC_DIR}/common 68 | ${TINYXML_DIR} 69 | PUBLIC 70 | ${INC_DIR} 71 | ) 72 | 73 | # install public headers 74 | install(DIRECTORY ${INC_DIR}/amdisa DESTINATION include COMPONENT dev) 75 | 76 | install(TARGETS isa_decoder EXPORT isa_decoderTargets 77 | ARCHIVE DESTINATION lib COMPONENT binary 78 | LIBRARY DESTINATION lib COMPONENT binary 79 | ) 80 | install(TARGETS isa_decoder_dynamic EXPORT isa_decoder_dynamicTargets 81 | 82 | ARCHIVE DESTINATION lib COMPONENT binary 83 | LIBRARY DESTINATION lib COMPONENT binary 84 | ) 85 | 86 | 87 | # Group these projects under an Examples folder. 88 | set_target_properties(isa_decoder isa_decoder_dynamic PROPERTIES FOLDER "libs") 89 | -------------------------------------------------------------------------------- /source/isa_explorer/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 2 | cmake_minimum_required(VERSION 3.0) 3 | 4 | # Setting project directories. 5 | set (SRC_DIR ../../source) 6 | set (INC_DIR ../../include) 7 | set (THIRD_PARTY_DIR ../third_party) 8 | 9 | # Control the path of tinyxml2. 10 | set (TINYXML_DIR ${THIRD_PARTY_DIR}/tinyxml2) 11 | if (TINYXML_SRC_PATH) 12 | message("-- IsaExplorer: Overwritting default tinyxml2 source files with ${TINYXML_SRC_PATH}") 13 | set (TINYXML_DIR ${TINYXML_SRC_PATH}) 14 | endif() 15 | 16 | # Redirect to single build output location 17 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output) 18 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output) 19 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output) 20 | 21 | # Local target: IsaDecoder. 22 | # Setting all header files for this project. 23 | set (ALL_H 24 | # Top interface header. 25 | ${INC_DIR}/amdisa/isa_explorer.h 26 | ${INC_DIR}/amdisa/api_version.h 27 | 28 | # Local library headers. 29 | ${SRC_DIR}/common/amdisa_structures.h 30 | ${SRC_DIR}/common/amdisa_utility.h 31 | ${SRC_DIR}/common/isa_xml_reader.h 32 | 33 | # Third party library headers. 34 | ${TINYXML_DIR}/tinyxml2.h 35 | ) 36 | 37 | # Setting all source files for this project. 38 | set (ALL_CPP 39 | # Top interface source file. 40 | ./isa_explorer.cpp 41 | 42 | # Local library source files. 43 | ${SRC_DIR}/common/amdisa_utility.cpp 44 | ${SRC_DIR}/common/amdisa_structures.cpp 45 | ${SRC_DIR}/common/isa_xml_reader.cpp 46 | 47 | # Third party source files. 48 | ${TINYXML_DIR}/tinyxml2.cpp 49 | ) 50 | 51 | # Adding target. 52 | add_library(isa_explorer STATIC ${ALL_CPP}) 53 | # Static Library 54 | target_include_directories(isa_explorer PRIVATE 55 | ${SRC_DIR}/common 56 | ${TINYXML_DIR} 57 | PUBLIC 58 | ${INC_DIR} 59 | ) 60 | 61 | 62 | # Dynamic Library 63 | add_library(isa_explorer_dynamic SHARED ${ALL_CPP}) 64 | target_include_directories(isa_explorer_dynamic PRIVATE 65 | ${SRC_DIR}/common 66 | ${TINYXML_DIR} 67 | PUBLIC 68 | ${INC_DIR} 69 | ) 70 | 71 | # install public headers 72 | install(DIRECTORY ${INC_DIR}/amdisa DESTINATION include COMPONENT dev) 73 | 74 | install(TARGETS isa_explorer EXPORT isa_explorerTargets 75 | ARCHIVE DESTINATION lib COMPONENT binary 76 | LIBRARY DESTINATION lib COMPONENT binary 77 | ) 78 | install(TARGETS isa_explorer_dynamic EXPORT isa_explorer_dynamicTargets 79 | 80 | ARCHIVE DESTINATION lib COMPONENT binary 81 | LIBRARY DESTINATION lib COMPONENT binary 82 | ) 83 | 84 | 85 | # Group these projects under an Examples folder. 86 | set_target_properties(isa_explorer isa_explorer_dynamic PROPERTIES FOLDER "libs") 87 | -------------------------------------------------------------------------------- /source/isa_spec_cli/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 2 | cmake_minimum_required(VERSION 3.0) 3 | 4 | # Setting project directories. 5 | set (SRC_DIR ../../source) 6 | set (THIRD_PARTY_DIR ../third_party) 7 | set (INC_DIR ../../include) 8 | 9 | # Control the path of tinyxml2. 10 | set (TINYXML_DIR ${THIRD_PARTY_DIR}/tinyxml2) 11 | if (TINYXML_SRC_PATH) 12 | message("-- IsaSpecCli: Overwritting default tinyxml2 source files with ${TINYXML_SRC_PATH}") 13 | set (TINYXML_DIR ${TINYXML_SRC_PATH}) 14 | endif() 15 | 16 | # Redirect to single build output location 17 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output) 18 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output) 19 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output) 20 | 21 | # Local target: IsaSpecCli. 22 | # Setting all header files for this project. 23 | set (ALL_H 24 | # CLI commands. 25 | ${SRC_DIR}/isa_spec_cli/cli_processor/cli_command.h 26 | ${SRC_DIR}/isa_spec_cli/cli_processor/cli_command_decode_machine_code.h 27 | ${SRC_DIR}/isa_spec_cli/cli_processor/cli_command_decode_shader_file.h 28 | ${SRC_DIR}/isa_spec_cli/cli_processor/cli_command_generate_inst_desc.h 29 | ${SRC_DIR}/isa_spec_cli/cli_processor/cli_command_get_inst_info.h 30 | ${SRC_DIR}/isa_spec_cli/cli_processor/cli_command_print_help.h 31 | ${SRC_DIR}/isa_spec_cli/cli_processor/cli_command_read_xml.h 32 | ${SRC_DIR}/isa_spec_cli/cli_processor/cli_processor.h 33 | ${SRC_DIR}/isa_spec_cli/cli_processor/public_cli_processor.h 34 | 35 | # ISA Spec decoder. 36 | ${INC_DIR}/amdisa/api_version.h 37 | ${INC_DIR}/amdisa/isa_decoder.h 38 | 39 | # Third party library headers. 40 | ${THIRD_PARTY_DIR}/cxxopts/cxxopts.hpp 41 | ${TINYXML_DIR}/tinyxml2.h 42 | ) 43 | 44 | # Setting all source files for this project. 45 | set (ALL_CPP 46 | # Local library headers. 47 | ${SRC_DIR}/isa_spec_cli/cli_processor/cli_command_decode_machine_code.cpp 48 | ${SRC_DIR}/isa_spec_cli/cli_processor/cli_command_decode_shader_file.cpp 49 | ${SRC_DIR}/isa_spec_cli/cli_processor/cli_command_get_inst_info.cpp 50 | ${SRC_DIR}/isa_spec_cli/cli_processor/cli_command_generate_inst_desc.cpp 51 | ${SRC_DIR}/isa_spec_cli/cli_processor/cli_command_print_help.cpp 52 | ${SRC_DIR}/isa_spec_cli/cli_processor/cli_command_read_xml.cpp 53 | ${SRC_DIR}/isa_spec_cli/cli_processor/public_cli_processor.cpp 54 | ) 55 | 56 | # Adding target. 57 | add_executable(isa_spec_cli main.cpp ${ALL_H} ${ALL_CPP}) 58 | target_include_directories(isa_spec_cli PRIVATE 59 | ${SRC_DIR}/common 60 | ${SRC_DIR}/isa_spec_cli/cli_processor 61 | ${THIRD_PARTY_DIR}/cxxopts 62 | ${TINYXML_DIR} 63 | PUBLIC 64 | ${INC_DIR}/amdisa 65 | ) 66 | target_link_libraries(isa_spec_cli PRIVATE 67 | isa_decoder 68 | ) 69 | 70 | install( 71 | TARGETS isa_spec_cli 72 | RUNTIME COMPONENT binary 73 | ) 74 | -------------------------------------------------------------------------------- /source/isa_spec_cli/cli_processor/cli_command.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | #ifndef I_CLI_COMMAND_H_ 5 | #define I_CLI_COMMAND_H_ 6 | 7 | // C++ libraries. 8 | #include 9 | 10 | namespace amdisa 11 | { 12 | // Interface class for commands. 13 | struct ICliCommand 14 | { 15 | ICliCommand() = default; 16 | virtual ~ICliCommand(){}; 17 | virtual bool Execute(std::string& err_message) = 0; 18 | }; 19 | } // namespace amdisa 20 | #endif // I_CLI_COMMAND_H_ 21 | -------------------------------------------------------------------------------- /source/isa_spec_cli/cli_processor/cli_command_decode_machine_code.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | #include "cli_command_decode_machine_code.h" 5 | 6 | // C++ libraries. 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | // Local libraries. 13 | #include "amdisa_utility.h" 14 | #include "amdisa/isa_decoder.h" 15 | 16 | namespace amdisa 17 | { 18 | // Constants. 19 | // Information constant strings. 20 | static const char* kStringInfoDecodeStart = "Info: Decoding..."; 21 | static const char* kStringInfoDecodeSuccessful = "Info: Decoding completed successfully."; 22 | 23 | // Error constant strings. 24 | static const char* kStringErrorDecodeFailed = "Error: Decoding failed."; 25 | static const char* kStringErrorInvalidInput = "Error: Invalid input."; 26 | 27 | bool CliCommandDecodeMachineCode::Execute(std::string& err_message) 28 | { 29 | bool is_executed = false; 30 | bool should_abort = false; 31 | 32 | std::cout << kStringInfoDecodeStart << std::endl; 33 | 34 | // Clean up the input. 35 | machine_code_.erase(std::remove_if(machine_code_.begin(), machine_code_.end(), [](const char c) { 36 | return c == '_' || std::isspace(c); 37 | }), machine_code_.end()); 38 | 39 | // Convert the string machine code into uints. 40 | std::vector machine_code_dwords; 41 | if (machine_code_.length() % 8 == 0) 42 | { 43 | for (size_t i = 0; i < machine_code_.length(); i += 8) 44 | { 45 | std::string single_dword = machine_code_.substr(i, 8); 46 | machine_code_dwords.push_back(std::strtoul(single_dword.c_str(), nullptr, 16)); 47 | } 48 | } 49 | else 50 | { 51 | std::stringstream err_stream; 52 | err_stream << kStringErrorDecodeFailed << " " << kStringErrorInvalidInput; 53 | err_message = err_stream.str(); 54 | should_abort = true; 55 | } 56 | 57 | if (!should_abort) 58 | { 59 | // API to decode instruction. 60 | std::string decode_err_message; 61 | std::vector instruction_info_stream; 62 | is_executed = spec_api_.DecodeInstructionStream(machine_code_dwords, instruction_info_stream, decode_err_message); 63 | 64 | // Print out. 65 | if (is_executed) 66 | { 67 | for (const auto& instruction_info_bundle : instruction_info_stream) 68 | { 69 | for (const auto& instruction_info : instruction_info_bundle.bundle) 70 | { 71 | std::cout << kStringInfoDecodeSuccessful << std::endl; 72 | std::cout << std::endl; 73 | 74 | // Print instruction in sp3-like format. 75 | std::cout << "Instruction: "; 76 | std::cout << instruction_info.instruction_name << std::endl; 77 | std::cout << "Operands: "; 78 | for (const auto& operand : instruction_info.instruction_operands) 79 | { 80 | std::cout << operand.operand_name << " "; 81 | } 82 | std::cout << std::endl; 83 | 84 | // Print instruction description. 85 | std::cout << "Description:" << std::endl; 86 | std::cout << instruction_info.instruction_description << std::endl; 87 | std::cout << std::endl; 88 | 89 | // Print encoding information. 90 | std::cout << " Encoding: " << instruction_info.encoding_name << std::endl; 91 | std::cout << instruction_info.encoding_layout << std::endl; 92 | std::cout << "===" << std::endl; 93 | } 94 | } 95 | } 96 | else 97 | { 98 | std::stringstream final_error; 99 | final_error << kStringErrorDecodeFailed << std::endl; 100 | final_error << decode_err_message << ". "; 101 | final_error << "Provided bits = " << machine_code_ << std::endl; 102 | err_message = final_error.str(); 103 | } 104 | } 105 | 106 | return is_executed; 107 | } 108 | } // namespace amdisa 109 | -------------------------------------------------------------------------------- /source/isa_spec_cli/cli_processor/cli_command_decode_machine_code.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | #ifndef CLI_COMMAND_DECODE_MACHINE_CODE_H_ 5 | #define CLI_COMMAND_DECODE_MACHINE_CODE_H_ 6 | 7 | // C++ libraries. 8 | #include 9 | 10 | // Local libraries. 11 | #include "cli_command.h" 12 | 13 | namespace amdisa 14 | { 15 | // Forward declarations. 16 | class IsaDecoder; 17 | 18 | /** 19 | * Class: CliCommandDecodeMachineCode 20 | * 21 | * Purpose: 22 | * This class is responsible for handling the CLI (Command Line Interface) command 23 | * that decodes instructions given in binary or machine code format. 24 | * 25 | * The instruction is expected to be provided as a string, and upon invocation, 26 | * the class decodes the instruction and provides a human-readable representation 27 | * of the corresponding assembly or high-level command. 28 | */ 29 | class CliCommandDecodeMachineCode : public ICliCommand 30 | { 31 | public: 32 | CliCommandDecodeMachineCode() = delete; 33 | CliCommandDecodeMachineCode(const std::string& machine_code, const IsaDecoder& spec_api) 34 | : machine_code_(machine_code) 35 | , spec_api_(spec_api) 36 | { 37 | } 38 | 39 | bool Execute(std::string& err_message) override; 40 | 41 | private: 42 | std::string machine_code_; 43 | const IsaDecoder& spec_api_; 44 | }; 45 | } // namespace amdisa 46 | #endif // CLI_COMMAND_DECODE_MACHINE_CODE_H_ 47 | -------------------------------------------------------------------------------- /source/isa_spec_cli/cli_processor/cli_command_decode_shader_file.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | #include "cli_command_decode_shader_file.h" 5 | 6 | // C++ libraries. 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | // Local libraries. 15 | #include "amdisa_utility.h" 16 | #include "amdisa_xml_element_consts.h" 17 | #include "amdisa/isa_decoder.h" 18 | 19 | // Third party libraries. 20 | #include "tinyxml2.h" 21 | 22 | using XMLDocument = tinyxml2::XMLDocument; 23 | using XMLElement = tinyxml2::XMLElement; 24 | 25 | namespace amdisa 26 | { 27 | // Constants. 28 | // Information constant strings. 29 | static const char* kStringInfoDecodeShaderFileStart = "Info: Decoding Shader file... "; 30 | static const char* kStringInfoDecodeShaderFileSuccessful = "Info: Decoding Shader file completed successfully."; 31 | 32 | // Error constant strings. 33 | static const char* kStringErrorDecodeFailed = "Error: Decoding Shader file failed."; 34 | static const char* kStringErrorXmlWriteFailed = "Error: Decoding Shader file failed. Could not write XML file."; 35 | 36 | // Creates a new XML element with a string value 37 | // and attachs to the parent XML element 38 | void AddToParentXmlElement(XMLElement* parent_element, const char* element_name, const char* value) 39 | { 40 | XMLDocument* XmlDoc = parent_element->GetDocument(); 41 | XMLElement* element_ptr = XmlDoc->NewElement(element_name); 42 | assert(element_ptr != nullptr); 43 | element_ptr->SetText(value); 44 | parent_element->InsertEndChild(element_ptr); 45 | } 46 | 47 | // Creates a new XML element with a uint64_t value 48 | // and attachs to the parent XML element 49 | void AddToParentXmlElement(XMLElement* parent_element, const char* element_name, const uint64_t& value) 50 | { 51 | XMLDocument* XmlDoc = parent_element->GetDocument(); 52 | XMLElement* element_ptr = XmlDoc->NewElement(element_name); 53 | assert(element_ptr != nullptr); 54 | element_ptr->SetText(value); 55 | parent_element->InsertEndChild(element_ptr); 56 | } 57 | 58 | // Removes whitespaces from the given string and returns the modified string 59 | std::string RemoveWhitespace(const std::string& str) 60 | { 61 | std::string str_no_ws = str; 62 | auto space_iter = std::find_if(str_no_ws.begin(), str_no_ws.end(), [](char ch) { return !std::isspace(ch, std::locale::classic()); }); 63 | str_no_ws.erase(str_no_ws.begin(), space_iter); 64 | auto space_iter_rev = std::find_if(str_no_ws.rbegin(), str_no_ws.rend(), [](char ch) { return !std::isspace(ch, std::locale::classic()); }); 65 | str_no_ws.erase(space_iter_rev.base(), str_no_ws.end()); 66 | return str_no_ws; 67 | } 68 | 69 | void PrintInstructionInfo(XMLElement* XmlInstructionInfo, const InstructionInfo& inst, bool is_branch_target_info_set = false) 70 | { 71 | XMLDocument* XmlDoc = XmlInstructionInfo->GetDocument(); 72 | XMLElement* parent_element; 73 | XMLElement* child_element; 74 | 75 | // Add Instruction Name XML Element 76 | AddToParentXmlElement(XmlInstructionInfo, kElementInstructionName, inst.instruction_name.c_str()); 77 | 78 | // Add Instruction Description XML Element 79 | AddToParentXmlElement(XmlInstructionInfo, kElementInstructionDescription, RemoveWhitespace(inst.instruction_description).c_str()); 80 | 81 | // Add Encoding Name XML Element 82 | AddToParentXmlElement(XmlInstructionInfo, kElementEncodingName, inst.encoding_name.c_str()); 83 | 84 | // Add Encoding Description XML Element 85 | AddToParentXmlElement(XmlInstructionInfo, kElementEncodingDescription, RemoveWhitespace(inst.encoding_description).c_str()); 86 | 87 | // Add Encoding Fields XML Element 88 | parent_element = XmlDoc->NewElement(kElementEncodingFields); 89 | assert(parent_element != nullptr); 90 | XmlInstructionInfo->InsertEndChild(parent_element); 91 | if (inst.encoding_fields.size()) 92 | { 93 | for (const auto& field : inst.encoding_fields) 94 | { 95 | child_element = XmlDoc->NewElement(kElementEncoding); 96 | assert(child_element != nullptr); 97 | AddToParentXmlElement(child_element, kElementName, field.field_name.c_str()); 98 | AddToParentXmlElement(child_element, kElementValue, field.field_value); 99 | AddToParentXmlElement(child_element, kElementBitCount, field.bit_count); 100 | AddToParentXmlElement(child_element, kElementBitOffset, field.bit_offset); 101 | parent_element->InsertEndChild(child_element); 102 | child_element = nullptr; 103 | } 104 | } 105 | else 106 | { 107 | parent_element->SetText("None"); 108 | } 109 | 110 | // Add Instruction Operands XML Element 111 | parent_element = XmlDoc->NewElement(kElementOperands); 112 | assert(parent_element != nullptr); 113 | XmlInstructionInfo->InsertEndChild(parent_element); 114 | if (inst.instruction_operands.size()) 115 | { 116 | for (const auto& operand : inst.instruction_operands) 117 | { 118 | child_element = XmlDoc->NewElement(kElementOperand); 119 | assert(child_element != nullptr); 120 | 121 | // Get operand name. 122 | std::string operand_to_print = operand.operand_name.c_str(); 123 | 124 | // Overwrite operand name with label if this is the branch. 125 | if (!inst.instruction_semantic_info.branch_info.branch_target_label.empty()) 126 | { 127 | operand_to_print = inst.instruction_semantic_info.branch_info.branch_target_label; 128 | } 129 | AddToParentXmlElement(child_element, kElementName, operand_to_print.c_str()); 130 | AddToParentXmlElement(child_element, kElementOperandSize, operand.operand_size); 131 | AddToParentXmlElement(child_element, kAttributeInput, (operand.is_input ? "yes" : "no")); 132 | AddToParentXmlElement(child_element, kAttributeOutput, (operand.is_output ? "yes" : "no")); 133 | parent_element->InsertEndChild(child_element); 134 | child_element = nullptr; 135 | } 136 | } 137 | else 138 | { 139 | parent_element->SetText("None"); 140 | } 141 | 142 | // Add Instruction Operand Modifiers XML Element 143 | parent_element = XmlDoc->NewElement(kElementOperandModifiers); 144 | assert(parent_element != nullptr); 145 | XmlInstructionInfo->InsertEndChild(parent_element); 146 | if (inst.operand_modifiers.size()) 147 | { 148 | for (const auto& modifier : inst.operand_modifiers) 149 | { 150 | child_element = XmlDoc->NewElement(kElementOperandModifier); 151 | AddToParentXmlElement(child_element, kElementName, modifier.modifier_name.c_str()); 152 | AddToParentXmlElement(child_element, kElementValue, modifier.value); 153 | parent_element->InsertEndChild(child_element); 154 | child_element = nullptr; 155 | } 156 | } 157 | else 158 | { 159 | parent_element->SetText("None"); 160 | } 161 | 162 | // Add Instruction Semantics XML Element 163 | parent_element = XmlDoc->NewElement(kElementInstructionSemantics); 164 | assert(parent_element != nullptr); 165 | XmlInstructionInfo->InsertEndChild(parent_element); 166 | AddToParentXmlElement(parent_element, kElementFlagIsBranch, (inst.instruction_semantic_info.branch_info.is_branch ? "yes" : "no")); 167 | AddToParentXmlElement(parent_element, kElementFlagIsProgramTerminator, (inst.instruction_semantic_info.is_program_terminator ? "yes" : "no")); 168 | AddToParentXmlElement(parent_element, kElementFlagIsImmediatelyExecuted, (inst.instruction_semantic_info.is_immediately_executed ? "yes" : "no")); 169 | 170 | child_element = XmlDoc->NewElement(kElementInstructionBranchInfo); 171 | assert(child_element != nullptr); 172 | XmlInstructionInfo->InsertEndChild(child_element); 173 | const BranchInfo* info = &inst.instruction_semantic_info.branch_info; 174 | bool is_branch = ((info != nullptr) && info->is_branch); 175 | AddToParentXmlElement( 176 | child_element, kElementFlagIsConditionalBranch, (((info != nullptr) && info->is_conditional) ? "yes" : (is_branch ? "no" : "N/A"))); 177 | AddToParentXmlElement(child_element, kElementFlagIsIndirectBranch, (((info != nullptr) && info->is_indirect) ? "yes" : (is_branch ? "no" : "N/A"))); 178 | AddToParentXmlElement(child_element, 179 | kElementInstructionBranchOffset, 180 | ((info != nullptr) && (info->branch_offset != kBranchOffsetOutOfRange)) ? std::to_string(info->branch_offset).c_str() : "N/A"); 181 | AddToParentXmlElement(child_element, 182 | kElementInstructionBranchTargetPC, 183 | (((info != nullptr) && !info->branch_target_pc.empty()) ? info->branch_target_pc.c_str() : "N/A")); 184 | AddToParentXmlElement(child_element, 185 | kElementInstructionBranchTargetLabel, 186 | (((info != nullptr) && !info->branch_target_label.empty()) ? info->branch_target_label.c_str() : "N/A")); 187 | AddToParentXmlElement( 188 | child_element, 189 | kElementInstructionBranchTargetIndex, 190 | (((info != nullptr) && info->branch_target_index != kInvalidBranchTarget) ? std::to_string(info->branch_target_index).c_str() : "N/A")); 191 | 192 | // Add Instruction's functional group and subgroup info 193 | parent_element = XmlDoc->NewElement(kElementFunctionalGroup); 194 | assert(parent_element != nullptr); 195 | XmlInstructionInfo->InsertEndChild(parent_element); 196 | AddToParentXmlElement(parent_element, kElementName, kFunctionalGroupName[static_cast(inst.functional_group_subgroup_info.IsaFunctionalGroup)]); 197 | AddToParentXmlElement( 198 | parent_element, kElementSubgroup, kFunctionalSubgroupName[static_cast(inst.functional_group_subgroup_info.IsaFunctionalSubgroup)]); 199 | AddToParentXmlElement(parent_element, kElementDescription, inst.functional_group_subgroup_info.description.c_str()); 200 | } 201 | 202 | bool CliCommandDecodeShaderFile::Execute(std::string& err_message) 203 | { 204 | bool is_executed = false; 205 | std::cout << kStringInfoDecodeShaderFileStart << shader_file_path_ << std::endl; 206 | 207 | // Capitalize info format for consistency. 208 | const std::string info_format_cap = AmdIsaUtility::ToUpper(info_format_); 209 | 210 | // API to decode instruction. 211 | std::string api_error_message; 212 | std::vector instruction_info_stream; 213 | bool is_decode_successful = 214 | spec_api_.DecodeShaderDisassemblyFile(shader_file_path_, instruction_info_stream, api_error_message, is_branch_target_info_set_); 215 | 216 | // Print out. 217 | if (is_decode_successful) 218 | { 219 | std::cout << kStringInfoDecodeShaderFileSuccessful << std::endl; 220 | if (info_format_cap == "XML") 221 | { 222 | // Variables used for generating output in XML format 223 | XMLDocument XmlOutput; 224 | XMLElement* XmlInfo = XmlOutput.NewElement("DecodedOutput"); 225 | XmlOutput.InsertFirstChild(XmlInfo); 226 | XMLElement* XmlInstructionInfos = XmlOutput.NewElement(kElementShaderInstructions); 227 | XmlInfo->InsertFirstChild(XmlInstructionInfos); 228 | uint32_t inst_order = 0; 229 | for (const auto& instruction_info_bundle : instruction_info_stream) 230 | { 231 | XMLElement* XmlInstructionInfo = XmlOutput.NewElement(kElementInstruction); 232 | AddToParentXmlElement(XmlInstructionInfo, kElementInstructionOrder, inst_order++); 233 | for (const auto& instruction_info : instruction_info_bundle.bundle) 234 | { 235 | PrintInstructionInfo(XmlInstructionInfo, instruction_info, is_branch_target_info_set_); 236 | } 237 | XmlInstructionInfos->InsertEndChild(XmlInstructionInfo); 238 | XmlInstructionInfo = nullptr; 239 | } 240 | if (!output_xml_path_.empty()) 241 | { 242 | tinyxml2::XMLError status = XmlOutput.SaveFile(output_xml_path_.c_str()); 243 | 244 | if (status == tinyxml2::XML_SUCCESS) 245 | { 246 | is_executed = true; 247 | } 248 | else 249 | { 250 | err_message = kStringErrorXmlWriteFailed; 251 | } 252 | } 253 | else 254 | { 255 | XmlOutput.Print(); 256 | is_executed = true; 257 | } 258 | } 259 | else 260 | { 261 | for (const auto& instruction_info_bundle : instruction_info_stream) 262 | { 263 | for (const auto& instruction_info : instruction_info_bundle.bundle) 264 | { 265 | std::cout << std::endl; 266 | 267 | // Print instruction in sp3-like format. 268 | std::cout << "Instruction: "; 269 | std::cout << std::setw(17) << std::left << instruction_info.instruction_name << " "; 270 | for (const auto& operand : instruction_info.instruction_operands) 271 | { 272 | std::cout << operand.operand_name << " "; 273 | } 274 | std::cout << std::endl; 275 | 276 | // Print instruction description. 277 | std::cout << "HTML Description:" << std::endl; 278 | std::cout << instruction_info.instruction_description << std::endl; 279 | std::cout << std::endl; 280 | 281 | // Print encoding information. 282 | std::cout << "Encoding: " << instruction_info.encoding_name << std::endl; 283 | std::cout << instruction_info.encoding_layout << std::endl; 284 | 285 | // Print about target if it's a direct branch. 286 | uint64_t target_index = instruction_info.instruction_semantic_info.branch_info.branch_target_index; 287 | if (target_index != amdisa::kInvalidBranchTarget) 288 | { 289 | std::cout << "Branch Target Information" << std::endl; 290 | amdisa::InstructionInfo target_inst_info; 291 | target_inst_info = instruction_info_stream[target_index].bundle[0]; 292 | 293 | // Print target instruction in sp3-like format. 294 | std::cout << "Target PC: " << instruction_info.instruction_semantic_info.branch_info.branch_target_pc << std::endl; 295 | std::cout << "Instruction: "; 296 | std::cout << std::setw(17) << std::left << target_inst_info.instruction_name << " "; 297 | for (const auto& operand : target_inst_info.instruction_operands) 298 | { 299 | std::cout << operand.operand_name << " "; 300 | } 301 | std::cout << std::endl; 302 | } 303 | 304 | // Print instruction's functional group and subgroup info 305 | std::cout << "Functional Group: " 306 | << kFunctionalGroupName[static_cast(instruction_info.functional_group_subgroup_info.IsaFunctionalGroup)] << std::endl; 307 | std::cout << "Functional Subgroup: " 308 | << kFunctionalSubgroupName[static_cast(instruction_info.functional_group_subgroup_info.IsaFunctionalSubgroup)] 309 | << std::endl; 310 | std::cout << "Functional Group Description: " << instruction_info.functional_group_subgroup_info.description << std::endl; 311 | 312 | std::cout << "===" << std::endl; 313 | } 314 | } 315 | is_executed = true; 316 | } 317 | } 318 | else 319 | { 320 | std::stringstream final_error; 321 | std::cerr << kStringErrorDecodeFailed << std::endl; 322 | std::cerr << api_error_message; 323 | } 324 | 325 | return is_executed; 326 | } 327 | } // namespace amdisa 328 | -------------------------------------------------------------------------------- /source/isa_spec_cli/cli_processor/cli_command_decode_shader_file.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | #ifndef CLI_COMMAND_DECODE_SHADER_FILE_H_ 5 | #define CLI_COMMAND_DECODE_SHADER_FILE_H_ 6 | 7 | // Local libraries. 8 | #include "cli_command.h" 9 | 10 | namespace amdisa 11 | { 12 | class IsaDecoder; 13 | 14 | /** 15 | * Class: CliCommandDecodeShaderFile 16 | * 17 | * Purpose: 18 | * This class is responsible for handling the CLI (Command Line Interface) command 19 | * that decodes shader files into a machine or human readable standardized format. 20 | * Given a shader file, the class provides the capability to decode its content 21 | * and save the result in various formats. Additionally, the class allows users 22 | * to specify the format of the decoding information and whether branch target 23 | * information should be included. 24 | */ 25 | class CliCommandDecodeShaderFile : public ICliCommand 26 | { 27 | public: 28 | CliCommandDecodeShaderFile(const std::string& shader_file_path, 29 | const std::string& output_xml_path, 30 | const std::string& info_format, 31 | const IsaDecoder& spec_api, 32 | bool is_branch_target_info_set) 33 | : info_format_(info_format) 34 | , shader_file_path_(shader_file_path) 35 | , output_xml_path_(output_xml_path) 36 | , spec_api_(spec_api) 37 | , is_branch_target_info_set_(is_branch_target_info_set){}; 38 | CliCommandDecodeShaderFile() = delete; 39 | 40 | bool Execute(std::string& err_message) override; 41 | 42 | private: 43 | const std::string info_format_; 44 | const std::string shader_file_path_; 45 | const std::string output_xml_path_; 46 | const IsaDecoder& spec_api_; 47 | const bool is_branch_target_info_set_; 48 | }; 49 | } // namespace amdisa 50 | #endif // CLI_COMMAND_DECODE_SHADER_FILE_H_ 51 | -------------------------------------------------------------------------------- /source/isa_spec_cli/cli_processor/cli_command_generate_inst_desc.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | #include "cli_command_generate_inst_desc.h" 5 | 6 | // C++ libraries. 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | // Local libraries. 14 | #include "amdisa_structures.h" 15 | #include "isa_xml_reader.h" 16 | 17 | namespace amdisa 18 | { 19 | enum class kSupportedFormat 20 | { 21 | kUndefined, 22 | kText, 23 | kCsv 24 | }; 25 | 26 | static const std::map kMapStringToSupportedFormats = {{"text", kSupportedFormat::kText}, {"csv", kSupportedFormat::kCsv}}; 27 | 28 | // Constants. 29 | static const char* kDescriptionTagOpen = ""; 30 | static const char* kDescriptionTagClose = ""; 31 | 32 | // Information constant strings. 33 | static const char* kStringInfoGenerateStart = "Info: Generating instruction descriptions..."; 34 | static const char* kStringInfoGenerateSuccessful = "Info: Instruction generation completed."; 35 | 36 | // Error constant strings. 37 | static const char* kStringErrorGenerateFailed = "Error: Instruction generation failed."; 38 | static const char* kStringErrorFileOpenFailed = "Error: Instruction generation failed. Could not open the file."; 39 | 40 | // Internal class to handle different printing formating. 41 | struct InstructionData 42 | { 43 | std::string instruction_name; 44 | std::string instruction_description; 45 | }; 46 | 47 | // Base class for the instruction serializer. 48 | class IInstructionSerializer 49 | { 50 | public: 51 | bool Initialize(const std::string& output_file_path) 52 | { 53 | desc_file_.open(output_file_path); 54 | is_init_ = desc_file_.is_open(); 55 | if (is_init_) 56 | { 57 | PrintHeader(); 58 | } 59 | return is_init_; 60 | } 61 | 62 | // Prints single line to file. 63 | virtual void PrintLine(const InstructionData& data) = 0; 64 | virtual ~IInstructionSerializer(){}; 65 | 66 | protected: 67 | std::ofstream desc_file_; 68 | bool is_init_ = false; 69 | 70 | // Prints the header of the file if the format requires. 71 | virtual void PrintHeader() = 0; 72 | }; 73 | 74 | // Print as text. 75 | class TextSerializer : public IInstructionSerializer 76 | { 77 | public: 78 | void PrintHeader() override 79 | { 80 | // This format does not have a header. 81 | } 82 | 83 | void PrintLine(const InstructionData& data) override 84 | { 85 | if (is_init_) 86 | { 87 | desc_file_ << data.instruction_name << std::endl; 88 | desc_file_ << data.instruction_description << std::endl; 89 | desc_file_ << std::endl; 90 | } 91 | } 92 | }; 93 | 94 | // Print as CSV. 95 | class CsvSerializer : public IInstructionSerializer 96 | { 97 | public: 98 | void PrintHeader() override 99 | { 100 | if (is_init_) 101 | { 102 | desc_file_ << "Instruction,Description\n"; 103 | } 104 | } 105 | 106 | void PrintLine(const InstructionData& data) override 107 | { 108 | if (is_init_) 109 | { 110 | std::string description = data.instruction_description.substr(0, data.instruction_description.length() - 1); 111 | desc_file_ << data.instruction_name << ","; 112 | desc_file_ << "\"" << description << "\"\r\n"; 113 | } 114 | } 115 | }; 116 | 117 | // Function for creating different types of printers. 118 | static std::shared_ptr GetSerializer(kSupportedFormat format) 119 | { 120 | std::shared_ptr ret; 121 | switch (format) 122 | { 123 | case kSupportedFormat::kCsv: 124 | ret = std::make_shared(); 125 | break; 126 | default: 127 | ret = std::make_shared(); 128 | break; 129 | } 130 | return ret; 131 | } 132 | 133 | bool CliCommandGenerateInstDesc::Execute(std::string& err_message) 134 | { 135 | bool is_executed = false; 136 | std::cout << kStringInfoGenerateStart << std::endl; 137 | 138 | // Pick the printing format. 139 | kSupportedFormat format = kSupportedFormat::kUndefined; 140 | if (kMapStringToSupportedFormats.count(desc_format_) > 0) 141 | { 142 | format = kMapStringToSupportedFormats.at(desc_format_); 143 | } 144 | std::shared_ptr serializer = GetSerializer(format); 145 | 146 | bool is_init = serializer->Initialize(output_desc_path_); 147 | if (is_init) 148 | { 149 | IsaSpec spec_data; 150 | std::string read_err_message; 151 | bool is_xml_read = IsaXmlReader::ReadSpec(input_xml_path_, spec_data, read_err_message); 152 | if (is_xml_read) 153 | { 154 | // Print instructions. 155 | for (const auto& instruction : spec_data.instructions) 156 | { 157 | // Remove opening description tag if present. 158 | std::string description = instruction.description; 159 | size_t open_pos = description.find(kDescriptionTagOpen); 160 | if (open_pos != std::string::npos) 161 | { 162 | description.erase(open_pos, strlen(kDescriptionTagOpen)); 163 | } 164 | 165 | // Remove closing description tag if present. 166 | size_t close_pos = description.find(kDescriptionTagClose); 167 | if (close_pos != std::string::npos) 168 | { 169 | description.erase(close_pos, strlen(kDescriptionTagClose)); 170 | } 171 | 172 | // Write to file. 173 | serializer->PrintLine({instruction.name, description}); 174 | } 175 | is_executed = true; 176 | std::cout << kStringInfoGenerateSuccessful << std::endl; 177 | } 178 | else 179 | { 180 | err_message = kStringErrorGenerateFailed; 181 | err_message += ". " + read_err_message; 182 | } 183 | } 184 | else 185 | { 186 | err_message = kStringErrorFileOpenFailed; 187 | } 188 | 189 | return is_executed; 190 | } 191 | } // namespace amdisa 192 | -------------------------------------------------------------------------------- /source/isa_spec_cli/cli_processor/cli_command_generate_inst_desc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | #ifndef CLI_COMMAND_GENERATE_INST_DESC_H_ 5 | #define CLI_COMMAND_GENERATE_INST_DESC_H_ 6 | 7 | // C++ libraries. 8 | #include 9 | 10 | // Local libraries. 11 | #include "cli_command.h" 12 | 13 | namespace amdisa 14 | { 15 | // Forward declarations. 16 | class IsaDecoder; 17 | 18 | /** 19 | * Class: CliCommandGenerateInstDesc 20 | * 21 | * Purpose: 22 | * This class is responsible for handling the CLI (Command Line Interface) command 23 | * that produces tables mapping instruction names to their corresponding descriptions. 24 | * Given the spec, the class can generate tables in various formats that provide a 25 | * description of each instruction. 26 | */ 27 | class CliCommandGenerateInstDesc : public ICliCommand 28 | { 29 | public: 30 | CliCommandGenerateInstDesc() = delete; 31 | CliCommandGenerateInstDesc(const std::string& output_desc_path, const std::string& input_xml_path, const std::string& desc_format) 32 | : output_desc_path_(output_desc_path) 33 | , input_xml_path_(input_xml_path) 34 | , desc_format_(desc_format) 35 | { 36 | } 37 | bool Execute(std::string& err_message) override; 38 | 39 | private: 40 | const std::string output_desc_path_; 41 | const std::string input_xml_path_; 42 | const std::string desc_format_; 43 | }; 44 | } // namespace amdisa 45 | #endif // CLI_COMMAND_GENERATE_INST_DESC_H_ 46 | -------------------------------------------------------------------------------- /source/isa_spec_cli/cli_processor/cli_command_get_inst_info.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | #include "cli_command_get_inst_info.h" 5 | 6 | // C++ libraries. 7 | #include 8 | #include 9 | #include 10 | 11 | // Local libraries. 12 | #include "amdisa_utility.h" 13 | #include "amdisa/isa_decoder.h" 14 | 15 | namespace amdisa 16 | { 17 | // Constants. 18 | // Information constant strings. 19 | static const char* kStringInfoInstructionRetrievalStart = "Info: Retrieving instruction information..."; 20 | static const char* kStringInfoInstructionRetrievalSuccessful = "Info: Instruction information retrieved successfully."; 21 | 22 | // Error constant strings. 23 | static const char* kStringErrorInstructionRetrievalFailed = "Error: Failed to retrieve instruction information."; 24 | 25 | bool CliCommandGetInstInfo::Execute(std::string& err_message) 26 | { 27 | bool is_executed = false; 28 | std::cout << kStringInfoInstructionRetrievalStart << std::endl; 29 | 30 | // API to get instruction information. 31 | std::string decode_err_message; 32 | InstructionInfo instruction_info; 33 | is_executed = spec_api_.DecodeInstruction(instruction_name_, instruction_info, decode_err_message); 34 | 35 | // Print out. 36 | if (is_executed) 37 | { 38 | std::cout << kStringInfoInstructionRetrievalSuccessful << std::endl; 39 | std::cout << std::endl; 40 | 41 | // Print instruction name. 42 | std::cout << "Instruction: " << instruction_info.instruction_name << std::endl; 43 | 44 | // Print instruction description. 45 | std::cout << "Description:" << std::endl; 46 | std::cout << instruction_info.instruction_description << std::endl; 47 | std::cout << std::endl; 48 | } 49 | else 50 | { 51 | std::stringstream final_error; 52 | final_error << kStringErrorInstructionRetrievalFailed << ". "; 53 | final_error << decode_err_message << ". "; 54 | final_error << "Instruction name = " << instruction_name_ << std::endl; 55 | err_message = final_error.str(); 56 | } 57 | 58 | return is_executed; 59 | } 60 | } // namespace amdisa 61 | -------------------------------------------------------------------------------- /source/isa_spec_cli/cli_processor/cli_command_get_inst_info.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | #ifndef CLI_COMMAND_GET_INST_INFO_H_ 5 | #define CLI_COMMAND_GET_INST_INFO_H_ 6 | 7 | // C++ libraries. 8 | #include 9 | 10 | // Local libraries. 11 | #include "cli_command.h" 12 | 13 | namespace amdisa 14 | { 15 | // Forward declarations. 16 | class IsaDecoder; 17 | 18 | /** 19 | * Class: CliCommandGetInstInfo 20 | * 21 | * Purpose: 22 | * This class is responsible for handling the CLI (Command Line Interface) command 23 | * that generates a detailed description or information about a given instruction. 24 | * Upon receiving an instruction, the class provides a comprehensive breakdown or 25 | * overview of what the instruction does, its operands, semantics, and other relevant details. 26 | */ 27 | class CliCommandGetInstInfo : public ICliCommand 28 | { 29 | public: 30 | CliCommandGetInstInfo(const std::string& instruction_name, const IsaDecoder& spec_api) 31 | : instruction_name_(instruction_name) 32 | , spec_api_(spec_api) 33 | { 34 | } 35 | CliCommandGetInstInfo() = delete; 36 | bool Execute(std::string& err_message) override; 37 | 38 | private: 39 | const std::string instruction_name_; 40 | const IsaDecoder& spec_api_; 41 | }; 42 | } // namespace amdisa 43 | #endif // CLI_COMMAND_GET_INST_INFO_H_ 44 | -------------------------------------------------------------------------------- /source/isa_spec_cli/cli_processor/cli_command_print_help.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | #include "cli_command_print_help.h" 5 | 6 | // C++ libraries. 7 | #include 8 | #include 9 | 10 | namespace amdisa 11 | { 12 | // Error constant strings. 13 | static const char* kStringErrorCommandNotConfigured = "Error: Print help command not configured."; 14 | 15 | bool CliCommandPrintHelp::Execute(std::string& err_message) 16 | { 17 | bool is_executed = false; 18 | if (!help_message_.empty()) 19 | { 20 | std::cout << help_message_ << std::endl; 21 | is_executed = true; 22 | } 23 | else 24 | { 25 | std::cerr << kStringErrorCommandNotConfigured << std::endl; 26 | } 27 | 28 | return is_executed; 29 | } 30 | } // namespace amdisa 31 | -------------------------------------------------------------------------------- /source/isa_spec_cli/cli_processor/cli_command_print_help.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | #ifndef CLI_COMMAND_PRINT_HELP_H_ 5 | #define CLI_COMMAND_PRINT_HELP_H_ 6 | 7 | // C++ libraries. 8 | #include 9 | 10 | // Local libraries. 11 | #include "cli_command.h" 12 | 13 | namespace amdisa 14 | { 15 | /** 16 | * Class: CliCommandPrintHelp 17 | * 18 | * Purpose: 19 | * This class is responsible for handling the CLI (Command Line Interface) command 20 | * that displays help or usage information to the user. It provides an overview 21 | * of available commands, their descriptions, and proper syntax or format for invoking them. 22 | */ 23 | class CliCommandPrintHelp : public ICliCommand 24 | { 25 | public: 26 | CliCommandPrintHelp() = delete; 27 | CliCommandPrintHelp(const std::string& help_message) 28 | : help_message_(help_message) 29 | { 30 | } 31 | bool Execute(std::string& err_message) override; 32 | 33 | private: 34 | std::string help_message_; 35 | }; 36 | } // namespace amdisa 37 | #endif // CLI_COMMAND_PRINT_HELP_H_ 38 | -------------------------------------------------------------------------------- /source/isa_spec_cli/cli_processor/cli_command_read_xml.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | #include "cli_command_read_xml.h" 5 | 6 | // C++ libraries. 7 | #include 8 | #include 9 | #include 10 | 11 | // Local libraries. 12 | #include "amdisa/isa_decoder.h" 13 | 14 | namespace amdisa 15 | { 16 | // Constants. 17 | // Information constant strings. 18 | static const char* kStringInfoXmlReadStart = "Info: Parsing XML file..."; 19 | static const char* kStringInfoXmlReadSuccessful = "Info: XML parsing completed successfully."; 20 | 21 | // Error constant strings. 22 | static const char* kStringErrorXmlReadFailed = "Error: Failed to parse XML file."; 23 | 24 | bool CliCommandReadXml::Execute(std::string& err_message) 25 | { 26 | bool is_executed = false; 27 | std::cout << kStringInfoXmlReadStart << std::endl; 28 | std::string init_err_message; 29 | is_executed = spec_api_.Initialize(input_xml_path_, init_err_message); 30 | 31 | if (is_executed) 32 | { 33 | std::cout << kStringInfoXmlReadSuccessful << std::endl; 34 | } 35 | else 36 | { 37 | std::stringstream final_error; 38 | final_error << kStringErrorXmlReadFailed << std::endl; 39 | final_error << init_err_message << std::endl; 40 | err_message = final_error.str(); 41 | } 42 | 43 | return is_executed; 44 | } 45 | } // namespace amdisa 46 | -------------------------------------------------------------------------------- /source/isa_spec_cli/cli_processor/cli_command_read_xml.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | #ifndef CLI_COMMAND_READ_XML_H_ 5 | #define CLI_COMMAND_READ_XML_H_ 6 | 7 | // C++ libraries. 8 | #include 9 | 10 | // Local libraries. 11 | #include "cli_command.h" 12 | 13 | namespace amdisa 14 | { 15 | // Forward declarations. 16 | class IsaDecoder; 17 | 18 | /** 19 | * Class: CliCommandReadXml 20 | * 21 | * Purpose: 22 | * This class is responsible for handling the CLI (Command Line Interface) command 23 | * that reads specification details from an XML file and populates internal data 24 | * structures with the extracted information. This operation facilitates the further 25 | * processing or utilization of the spec details within the application. 26 | */ 27 | class CliCommandReadXml : public ICliCommand 28 | { 29 | public: 30 | CliCommandReadXml(const std::string& input_xml_path, IsaDecoder& spec_api) 31 | : input_xml_path_(input_xml_path) 32 | , spec_api_(spec_api) 33 | { 34 | } 35 | CliCommandReadXml() = delete; 36 | bool Execute(std::string& err_message) override; 37 | 38 | private: 39 | std::string input_xml_path_; 40 | IsaDecoder& spec_api_; 41 | }; 42 | } // namespace amdisa 43 | #endif // CLI_COMMAND_READ_XML_H_ 44 | -------------------------------------------------------------------------------- /source/isa_spec_cli/cli_processor/cli_processor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | #ifndef CLI_PROCESSOR_H_ 5 | #define CLI_PROCESSOR_H_ 6 | 7 | // Forward declarations. 8 | namespace cxxopts 9 | { 10 | class Options; 11 | class ParseResult; 12 | } // namespace cxxopts 13 | 14 | namespace amdisa 15 | { 16 | // Forward declarations. 17 | class IsaDecoder; 18 | 19 | // Interface class for CLI programs. 20 | struct ICliProcessor 21 | { 22 | ICliProcessor() = default; 23 | virtual ~ICliProcessor(){}; 24 | 25 | // Adds options specific to the CLI implementation. 26 | virtual void AppendOptions(cxxopts::Options& options) = 0; 27 | 28 | // Creates relevant commands based on the options. 29 | virtual void Configure(const cxxopts::ParseResult& arguments, const std::string& cli_help_msg, IsaDecoder& spec_api) = 0; 30 | 31 | // Run. 32 | virtual void Run() = 0; 33 | }; 34 | } // namespace amdisa 35 | #endif // CLI_PROCESSOR_H_ 36 | -------------------------------------------------------------------------------- /source/isa_spec_cli/cli_processor/public_cli_processor.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | #include "public_cli_processor.h" 5 | 6 | // C++ libraries. 7 | #include 8 | #include 9 | 10 | // Local libraries. 11 | #include "amdisa/isa_decoder.h" 12 | 13 | // Third party libraries. 14 | #include "cxxopts.hpp" 15 | 16 | // Include CLI command implementations that belong to this CLI. 17 | #include "cli_command_decode_machine_code.h" 18 | #include "cli_command_decode_shader_file.h" 19 | #include "cli_command_generate_inst_desc.h" 20 | #include "cli_command_get_inst_info.h" 21 | #include "cli_command_print_help.h" 22 | #include "cli_command_read_xml.h" 23 | 24 | namespace amdisa 25 | { 26 | // List of options for this CLI processor. 27 | // Argument to get help message. 28 | static const char* kArgHelp = "help"; 29 | static const char* kArgHelpMsg = "Print help."; 30 | static const char kArgHelp_short = 'h'; 31 | 32 | // Input XML file. 33 | static const char* kArgInputXml = "xml"; 34 | static const char* kArgInputXmlMsg = "Path to input XML file."; 35 | static const char kArgInputXml_short = 'x'; 36 | 37 | // Shader Decode Output XML file. 38 | static const char* kArgOutputXml = "shader_output_xml"; 39 | static const char* kArgOutputXmlMsg = "Path to output XML file generated by shader decoding."; 40 | static const char kArgOutputXml_short = 'e'; 41 | 42 | // Decode the machine code into the instruction 43 | static const char* kArgDecodeBits = "decode_bits"; 44 | static const char* kArgDecodeBitsMsg = "Decode the given machine code. Should be in hex and a multiple of 32-bits. Examples: -d DD05800001000002, -d DD058000_01000002, -d 76020EF2"; 45 | static const char kArgDecodeBits_short = 'd'; 46 | 47 | // Get instruction information. 48 | static const char* kArgGetInstructionInfo = "instruction_info"; 49 | static const char* kArgGetInstructionInfoMsg = "Get information on the given instruction (Input: instruction name)."; 50 | static const char kArgGetInstructionInfo_short = 'i'; 51 | 52 | // Decode the whole shader disassembly file 53 | static const char* kArgDecodeShaderFile = "shader_file"; 54 | static const char* kArgDecodeShaderFileMsg = "Path to shader disassembly file(sp3 / LLVM)"; 55 | static const char kArgDecodeShaderFile_short = 'f'; 56 | 57 | // Decode the whole shader disassembly file 58 | static const char* kArgDecodeShaderFileBranchInfo = "branch_info"; 59 | static const char* kArgDecodeShaderFileBranchInfoMsg = "Enable direct branch targets information for shader file decoding."; 60 | static const char kArgDecodeShaderFileBranchInfo_short = 'b'; 61 | 62 | // Decode the whole shader disassembly file 63 | static const char* kArgDecodeInfoFormat = "info_format"; 64 | static const char* kArgDecodeInfoFormatMsg = "Define shader disassembly instruction information XML output format"; 65 | static const char kArgDecodeInfoFormat_short = 'p'; 66 | 67 | // Generate instruction description file. 68 | static const char* kArgGenInstDescriptions = "gen_desc"; 69 | static const char* kArgGenInstDescriptionsMsg = "Path to output file with instruction-to-description mappings."; 70 | static const char kArgGenInstDescriptions_short = 'g'; 71 | 72 | // Specify the format of generated instruction descriptions. 73 | static const char* kArgInstDescriptionFormat = "desc_format"; 74 | static const char* kArgInstDescriptionsFormatMsg = "Format of the generated instruction descriptions (Ex.: --desc_format=csv)"; 75 | static const char kArgInstDescriptionsFormat_short = 't'; 76 | 77 | // Hiding implementation details of this class. 78 | struct PublicCliProcessor::PublicCliProcessorImpl 79 | { 80 | PublicCliProcessorImpl(IsaDecoder& spec_api) 81 | : spec_api(spec_api) 82 | { 83 | } 84 | std::vector> commands; 85 | IsaDecoder& spec_api; 86 | }; 87 | 88 | PublicCliProcessor::~PublicCliProcessor() 89 | { 90 | if (pimpl_ != nullptr) 91 | { 92 | delete pimpl_; 93 | pimpl_ = nullptr; 94 | } 95 | } 96 | 97 | void PublicCliProcessor::AppendOptions(cxxopts::Options& options) 98 | { 99 | // Form the arguments. 100 | std::stringstream help_args; 101 | std::stringstream xml_in_args; 102 | std::stringstream xml_out_args; 103 | std::stringstream decode_bits_args; 104 | std::stringstream get_inst_info_args; 105 | std::stringstream shader_file_args; 106 | std::stringstream branch_target_info_args; 107 | std::stringstream info_format_args; 108 | std::stringstream gen_inst_desc_args; 109 | std::stringstream inst_desc_format_args; 110 | 111 | help_args << kArgHelp_short << "," << kArgHelp; 112 | xml_in_args << kArgInputXml_short << "," << kArgInputXml; 113 | xml_out_args << kArgOutputXml_short << "," << kArgOutputXml; 114 | decode_bits_args << kArgDecodeBits_short << "," << kArgDecodeBits; 115 | get_inst_info_args << kArgGetInstructionInfo_short << "," << kArgGetInstructionInfo; 116 | shader_file_args << kArgDecodeShaderFile_short << "," << kArgDecodeShaderFile; 117 | branch_target_info_args << kArgDecodeShaderFileBranchInfo_short << "," << kArgDecodeShaderFileBranchInfo; 118 | info_format_args << kArgDecodeInfoFormat_short << "," << kArgDecodeInfoFormat; 119 | gen_inst_desc_args << kArgGenInstDescriptions_short << "," << kArgGenInstDescriptions; 120 | inst_desc_format_args << kArgInstDescriptionsFormat_short << "," << kArgInstDescriptionFormat; 121 | 122 | options.add_options()(help_args.str(), kArgHelpMsg)(xml_in_args.str(), kArgInputXmlMsg, cxxopts::value())( 123 | decode_bits_args.str(), kArgDecodeBitsMsg, cxxopts::value())( 124 | get_inst_info_args.str(), kArgGetInstructionInfoMsg, cxxopts::value())( 125 | shader_file_args.str(), kArgDecodeShaderFileMsg, cxxopts::value())( 126 | branch_target_info_args.str(), kArgDecodeShaderFileBranchInfoMsg, cxxopts::value())( 127 | xml_out_args.str(), kArgOutputXmlMsg, cxxopts::value())( 128 | info_format_args.str(), kArgDecodeInfoFormatMsg, cxxopts::value())( 129 | gen_inst_desc_args.str(), kArgGenInstDescriptionsMsg, cxxopts::value())( 130 | inst_desc_format_args.str(), kArgInstDescriptionsFormatMsg, cxxopts::value()); 131 | 132 | // Options that could be both in public and internal. 133 | options.add_options(); 134 | } 135 | 136 | // Creates relevant commands based on the options. 137 | void PublicCliProcessor::Configure(const cxxopts::ParseResult& arguments, const std::string& cli_help_msg, IsaDecoder& spec_api) 138 | { 139 | pimpl_ = new PublicCliProcessorImpl(spec_api); 140 | 141 | // Print help message if user asked. 142 | if (arguments.count(kArgHelp) > 0) 143 | { 144 | pimpl_->commands.push_back(std::make_unique(cli_help_msg)); 145 | } 146 | 147 | // Read XML. 148 | if (arguments.count(kArgInputXml) > 0) 149 | { 150 | pimpl_->commands.push_back(std::make_unique(arguments[kArgInputXml].as(), pimpl_->spec_api)); 151 | } 152 | 153 | // Decode binary instruction. 154 | if (arguments.count(kArgDecodeBits) > 0) 155 | { 156 | pimpl_->commands.push_back(std::make_unique(arguments[kArgDecodeBits].as(), pimpl_->spec_api)); 157 | } 158 | 159 | // Request instruction information. 160 | if (arguments.count(kArgGetInstructionInfo) > 0) 161 | { 162 | pimpl_->commands.push_back( 163 | std::make_unique(arguments[kArgGetInstructionInfo].as(), pimpl_->spec_api)); 164 | } 165 | 166 | // Decode shader file. 167 | if (arguments.count(kArgDecodeShaderFile) > 0) 168 | { 169 | const std::string shader_file = arguments[kArgDecodeShaderFile].as(); 170 | const bool branch_target_info = arguments.count(kArgDecodeShaderFileBranchInfo) > 0; 171 | 172 | // Two more options become relevant if we are decoding shader. 173 | std::string output_xml; 174 | if (arguments.count(kArgOutputXml) > 0) 175 | { 176 | output_xml = arguments[kArgOutputXml].as(); 177 | } 178 | std::string info_format; 179 | if (arguments.count(kArgDecodeInfoFormat) > 0) 180 | { 181 | info_format = arguments[kArgDecodeInfoFormat].as(); 182 | } 183 | pimpl_->commands.push_back( 184 | std::make_unique(shader_file, output_xml, info_format, pimpl_->spec_api, branch_target_info)); 185 | } 186 | 187 | // Generate instruction descriptions. 188 | if (arguments.count(kArgGenInstDescriptions) > 0 && arguments.count(kArgInputXml) > 0) 189 | { 190 | std::string desc_format; 191 | if (arguments.count(kArgInstDescriptionFormat) > 0) 192 | { 193 | desc_format = arguments[kArgInstDescriptionFormat].as(); 194 | } 195 | std::string input_xml_path = arguments[kArgInputXml].as(); 196 | std::string output_desc_path = arguments[kArgGenInstDescriptions].as(); 197 | pimpl_->commands.push_back(std::make_unique(output_desc_path, input_xml_path, desc_format)); 198 | } 199 | } 200 | 201 | void PublicCliProcessor::Run() 202 | { 203 | for (const auto& command : pimpl_->commands) 204 | { 205 | std::string err_message; 206 | bool is_executed = command->Execute(err_message); 207 | if (!is_executed) 208 | { 209 | std::cerr << err_message << std::endl; 210 | } 211 | } 212 | } 213 | 214 | } // namespace amdisa 215 | 216 | -------------------------------------------------------------------------------- /source/isa_spec_cli/cli_processor/public_cli_processor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | #ifndef PUBLIC_CLI_PROCESSOR_H_ 5 | #define PUBLIC_CLI_PROCESSOR_H_ 6 | 7 | // C++ libraries. 8 | #include 9 | #include 10 | #include 11 | 12 | // Local libraries. 13 | #include "cli_command.h" 14 | #include "cli_processor.h" 15 | 16 | // Forward declaration. 17 | namespace cxxopts 18 | { 19 | class Options; 20 | class ParseResult; 21 | } // namespace cxxopts 22 | 23 | namespace amdisa 24 | { 25 | // Forward declarations. 26 | class IsaDecoder; 27 | 28 | class PublicCliProcessor : public ICliProcessor 29 | { 30 | public: 31 | PublicCliProcessor() = default; 32 | ~PublicCliProcessor(); 33 | void AppendOptions(cxxopts::Options& options) override; 34 | void Configure(const cxxopts::ParseResult& arguments, const std::string& cli_help_msg, IsaDecoder& spec_api) override; 35 | void Run() override; 36 | 37 | private: 38 | struct PublicCliProcessorImpl; 39 | PublicCliProcessorImpl* pimpl_ = nullptr; 40 | }; 41 | } // namespace amdisa 42 | #endif // PUBLIC_CLI_PROCESSOR_H_ 43 | -------------------------------------------------------------------------------- /source/isa_spec_cli/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | // Local libraries. 5 | #include "isa_decoder.h" 6 | #include "public_cli_processor.h" 7 | 8 | // Third party libraries. 9 | #include "cxxopts.hpp" 10 | 11 | // Constants. 12 | // Error messages. 13 | static const char* kStringErrorParsingCommandLineArgs = "Error: Failed to parse command line arguments."; 14 | // Info messages. 15 | static const char* kStringInfoCliDescription = "Command line interface program for ISA Spec API."; 16 | 17 | int main(int argc, char* argv[]) 18 | { 19 | amdisa::IsaDecoder spec_api; 20 | amdisa::PublicCliProcessor public_cli_proc; 21 | cxxopts::Options options(argv[0], kStringInfoCliDescription); 22 | 23 | // Configure CLI. 24 | bool should_abort = false; 25 | try 26 | { 27 | public_cli_proc.AppendOptions(options); 28 | public_cli_proc.Configure(options.parse(argc, argv), options.help(), spec_api); 29 | } 30 | catch (const cxxopts::OptionException& e) 31 | { 32 | std::cerr << kStringErrorParsingCommandLineArgs << std::endl; 33 | std::cerr << " Exception: " << e.what() << std::endl; 34 | std::cerr << std::endl; 35 | std::cerr << options.help() << std::endl; 36 | should_abort = true; 37 | } 38 | 39 | // Run CLI. 40 | if (!should_abort) 41 | { 42 | public_cli_proc.Run(); 43 | } 44 | return 0; 45 | } 46 | -------------------------------------------------------------------------------- /test/run_unit_tests.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2024-2025 Advanced Micro Devices, Inc. All rights reserved. 2 | from optparse import OptionParser 3 | import os 4 | import subprocess 5 | 6 | # Option help messages. 7 | HELP_MSG_AMDISA_TEST_BIN_PATH = 'AMDISA unit test executable path' 8 | HELP_XML_FILE_PATH = 'AMDISA XML file path' 9 | HELP_XML_DIR_PATH_OUTPUT = 'AMDISA XML files directory path' 10 | 11 | # Error messages. 12 | ERR_MSG_INVALID_ARGUMENTS = 'Invalid arguments provided: ' 13 | ERR_MSG_NO_TEST_FILE_OR_DIR_PROVIDED = 'No AMDISA XML test file or file directory provided' 14 | ERR_MSG_AMDISA_TEST_BIN_NOT_PROVIDED = 'AMDISA test executable not provided' 15 | ERR_MSG_EXE_DOES_NOT_EXIST = 'AMDISA test executable does not exists: {}' 16 | ERR_MSG_XML_FILE_DOES_NOT_EXIST = 'AMDISA XML file path does not exists: {}' 17 | ERR_MSG_NOT_XML_FILE = 'The provided file type is not supported' 18 | ERR_MSG_NO_XML_FILES_FOUND = 'No XML files found in the provided test directory: {}' 19 | ERR_MSG_XMLS_DIR_NOT_EXIST = 'AMDISA XMLs directory path does not exists: {}' 20 | ERR_MSG_XML_UNIT_TEST_FAIL = 'Unit tests FAILED for {}' 21 | 22 | # Info messages. 23 | INFO_ALL_XMLS_UNIT_TESTS_PASSED = "Unit tests PASSED!" 24 | 25 | # Executable command 26 | AMDISA_TEST_CMD = '{} -I {}' 27 | 28 | # Parse arguments 29 | def parse_args(): 30 | 31 | # Setup OptionParser 32 | parser = OptionParser() 33 | parser.add_option("-e", "--test-path", dest="amdisa_test", help=HELP_MSG_AMDISA_TEST_BIN_PATH) 34 | parser.add_option("-f", "--xml-file", dest="xml_file_path", help=HELP_XML_FILE_PATH) 35 | parser.add_option("-d", "--dir", dest="xmls_dir_path", help=HELP_XML_DIR_PATH_OUTPUT) 36 | (options, args) = parser.parse_args() 37 | 38 | # Initialize parse variables 39 | is_parse_successful = False 40 | error_message = ERR_MSG_INVALID_ARGUMENTS 41 | exec_path = "" 42 | xml_file = "" 43 | xml_files_dir = "" 44 | 45 | if not options.amdisa_test: 46 | # Path to amdisa_test required 47 | error_message += ERR_MSG_AMDISA_TEST_BIN_NOT_PROVIDED 48 | else: 49 | # Parse amdisa_test path and check if exists 50 | if not options.amdisa_test is None: 51 | if os.path.exists(options.amdisa_test): 52 | is_parse_successful = True 53 | exec_path = options.amdisa_test 54 | else: 55 | error_message += ERR_MSG_EXE_DOES_NOT_EXIST.format(options.amdisa_test) 56 | 57 | # Parse xml file path or xmls directory path and check if exists 58 | if (is_parse_successful and (options.xml_file_path or options.xmls_dir_path)): 59 | if not options.xml_file_path is None: 60 | if os.path.exists(options.xml_file_path): 61 | xml_file = options.xml_file_path 62 | else: 63 | is_parse_successful = False 64 | error_message += ERR_MSG_XML_FILE_DOES_NOT_EXIST.format(options.xml_file_path) 65 | 66 | if not options.xmls_dir_path is None: 67 | if os.path.exists(options.xmls_dir_path): 68 | xml_files_dir = options.xmls_dir_path 69 | else: 70 | is_parse_successful = False 71 | error_message += ERR_MSG_XMLS_DIR_NOT_EXIST.format(options.xmls_dir_path) 72 | else: 73 | # Fail if no xml file path or xmls dir path is provided 74 | is_parse_successful = False 75 | error_message += ERR_MSG_NO_TEST_FILE_OR_DIR_PROVIDED 76 | 77 | # Print help 78 | if not is_parse_successful: 79 | parser.print_help() 80 | 81 | return is_parse_successful, error_message, exec_path, xml_file, xml_files_dir 82 | 83 | # Perform unit tests on AMDISA XML file 84 | def test_xml_file(exec_path, spec_file): 85 | is_pass = False 86 | file_name = os.path.basename(spec_file).split('/')[-1] 87 | error_message = ERR_MSG_XML_UNIT_TEST_FAIL.format(file_name) 88 | if file_name.endswith(".xml"): 89 | cli_command = AMDISA_TEST_CMD.format(exec_path, spec_file).split() 90 | test = subprocess.Popen(cli_command) 91 | test.communicate() 92 | is_pass = (test.returncode == 0) 93 | else: 94 | # Fail if an AMDISA XML file is not provided 95 | error_message += ": " + ERR_MSG_NOT_XML_FILE 96 | 97 | return is_pass, error_message 98 | 99 | # Perform unit tests on all the AMDISA XML files in the given directory 100 | def test_xml_files_dir(exec_path, xml_files_dir): 101 | is_pass = False 102 | error_message = ERR_MSG_NO_XML_FILES_FOUND.format(xml_files_dir) 103 | for xml_file in os.listdir(xml_files_dir): 104 | if xml_file.endswith(".xml"): 105 | is_pass, error_message = test_xml_file(exec_path, os.path.join(xml_files_dir, xml_file)) 106 | if not is_pass: 107 | # Exit even if one of the AMDISA XML file fails the unit tests 108 | break 109 | return is_pass, error_message 110 | 111 | def main(): 112 | is_pass = False 113 | error_message = "" 114 | 115 | # Parse arguments 116 | is_pass, error_message, exec_path, xml_file, xml_files_dir = parse_args() 117 | 118 | # Test AMDISA XML file or AMDISA XML directory 119 | if is_pass: 120 | if xml_file: 121 | is_pass, error_message = test_xml_file(exec_path, xml_file) 122 | if xml_files_dir: 123 | is_pass, error_message = test_xml_files_dir(exec_path, xml_files_dir) 124 | 125 | if is_pass: 126 | print(INFO_ALL_XMLS_UNIT_TESTS_PASSED) 127 | else: 128 | print(error_message) 129 | exit(1) 130 | 131 | if __name__ == "__main__": 132 | main() 133 | -------------------------------------------------------------------------------- /test/source/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 2 | cmake_minimum_required(VERSION 3.0) 3 | 4 | # Setting project directories. 5 | set (SRC_DIR ../source) 6 | set (THIRD_PARTY_DIR ../third_party) 7 | 8 | # Redirect to single build output location 9 | set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output) 10 | set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output) 11 | set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output) 12 | 13 | # Local target: IsaSpecCli. 14 | # Setting all header files for this project. 15 | set (ALL_H 16 | ${SRC_DIR}/include/amdisa_tests.h 17 | # Third party library headers. 18 | ${THIRD_PARTY_DIR}/catch2/catch.hpp 19 | ) 20 | 21 | # Setting all test files for this project. 22 | set (ALL_TESTS_CPP 23 | # Test files 24 | test_initialize.cpp 25 | test_decode_inst.cpp 26 | test_decode_text.cpp 27 | ) 28 | 29 | # Adding target. 30 | add_executable(amdisa_test main.cpp ${ALL_H} ${ALL_TESTS_CPP}) 31 | target_include_directories(amdisa_test PRIVATE 32 | ${SRC_DIR}/include 33 | ${THIRD_PARTY_DIR}/catch2 34 | ) 35 | target_link_libraries(amdisa_test PRIVATE 36 | isa_decoder 37 | ) 38 | 39 | install( 40 | TARGETS amdisa_test 41 | RUNTIME COMPONENT binary 42 | ) 43 | -------------------------------------------------------------------------------- /test/source/include/amdisa_tests.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | 5 | #ifndef AMDISA_TESTS_H_ 6 | #define AMDISA_TESTS_H_ 7 | 8 | #include "amdisa/isa_decoder.h" 9 | 10 | class TestConfig 11 | { 12 | public: 13 | TestConfig(const TestConfig&) = delete; 14 | TestConfig& operator=(const TestConfig&) = delete; 15 | 16 | static TestConfig& getInstance() 17 | { 18 | static TestConfig instance; 19 | return instance; 20 | } 21 | 22 | const std::string& GetXmlPath() 23 | { 24 | return xml_path_; 25 | }; 26 | 27 | void SetXmlPath(std::string path){ 28 | xml_path_ = path; 29 | }; 30 | 31 | private: 32 | TestConfig() = default; 33 | std::string xml_path_; 34 | }; 35 | 36 | #endif // AMDISA_TESTS_H_ 37 | -------------------------------------------------------------------------------- /test/source/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | 5 | #include "amdisa_tests.h" 6 | 7 | #define CATCH_CONFIG_RUNNER 8 | #include "catch.hpp" 9 | 10 | int main(int argc, char* argv[]) 11 | { 12 | Catch::Session session; 13 | 14 | std::string xml_path; 15 | std::string disassembly_file; 16 | 17 | using namespace Catch::clara; 18 | auto cli = session.cli() | Opt(xml_path, "spec")["-I"]["--spec"]("Path to the AMDISA XML spec [REQUIRED]") | 19 | Opt(disassembly_file, "disassembly_file")["-F"]["--disassembly"]("Path to the binary disassembly input file [OPTIONAL]"); 20 | 21 | session.cli(cli); 22 | 23 | int returnCode = session.applyCommandLine(argc, argv); 24 | if (returnCode != 0) 25 | return returnCode; 26 | 27 | TestConfig& config = TestConfig::getInstance(); 28 | if (!xml_path.empty()) 29 | { 30 | config.SetXmlPath(xml_path); 31 | std::cout << "Testing: " << xml_path << std::endl; 32 | } 33 | 34 | return session.run(); 35 | } 36 | -------------------------------------------------------------------------------- /test/source/test_decode_inst.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | // C++ libraries. 5 | #include 6 | 7 | // Local libraries. 8 | #include "amdisa_tests.h" 9 | #include "amdisa/isa_decoder.h" 10 | #include "catch.hpp" 11 | 12 | // Define machine code to assembly code mapping for different architectures. 13 | static void GetTestCaseSingle(const amdisa::GpuArchitecture architecture, 14 | uint32_t& machine_code, std::string& instruction_name) 15 | { 16 | machine_code = 0x80000002; 17 | instruction_name = "S_ADD_U32"; 18 | if (architecture == amdisa::GpuArchitecture::kRdna4) 19 | { 20 | instruction_name = "S_ADD_CO_U32"; 21 | } 22 | } 23 | 24 | static void GetTestCaseStream(const amdisa::GpuArchitecture architecture, 25 | std::vector& machine_code_stream, std::string& instruction_name) 26 | { 27 | machine_code_stream = { 0x801FFF1F, 0x00000000 }; 28 | instruction_name = "S_ADD_U32"; 29 | if (architecture == amdisa::GpuArchitecture::kRdna4) 30 | { 31 | instruction_name = "S_ADD_CO_U32"; 32 | } 33 | } 34 | 35 | TEST_CASE("Test to decode of a single instruction name", "[decode][single]") 36 | { 37 | amdisa::IsaDecoder decoder; 38 | std::string msg; 39 | TestConfig& config = TestConfig::getInstance(); 40 | REQUIRE(decoder.Initialize(config.GetXmlPath(), msg)); 41 | 42 | amdisa::InstructionInfo info; 43 | REQUIRE(decoder.DecodeInstruction("S_MOV_B32", info, msg)); 44 | REQUIRE(info.instruction_name == "S_MOV_B32"); 45 | } 46 | 47 | TEST_CASE("Test to decode of a single instruction binary", "[decode][single]") 48 | { 49 | amdisa::IsaDecoder decoder; 50 | std::string msg; 51 | TestConfig& config = TestConfig::getInstance(); 52 | REQUIRE(decoder.Initialize(config.GetXmlPath(), msg)); 53 | 54 | const auto kArchitecture = decoder.GetArchitecture(); 55 | REQUIRE(kArchitecture != amdisa::GpuArchitecture::kUnknown); 56 | 57 | uint32_t machine_code = 0; 58 | std::string expected_instruction_name; 59 | GetTestCaseSingle(kArchitecture, machine_code, expected_instruction_name); 60 | 61 | amdisa::InstructionInfoBundle info; 62 | REQUIRE(decoder.DecodeInstruction(machine_code, info, msg)); 63 | REQUIRE(info.bundle[0].instruction_name == expected_instruction_name); 64 | } 65 | 66 | TEST_CASE("Test to decode of an instruction stream", "[decode][single]") 67 | { 68 | amdisa::IsaDecoder decoder; 69 | std::string msg; 70 | TestConfig& config = TestConfig::getInstance(); 71 | REQUIRE(decoder.Initialize(config.GetXmlPath(), msg)); 72 | 73 | const auto kArchitecture = decoder.GetArchitecture(); 74 | REQUIRE(kArchitecture != amdisa::GpuArchitecture::kUnknown); 75 | 76 | std::vector machine_code_stream; 77 | std::string expected_instruction_name; 78 | GetTestCaseStream(kArchitecture, machine_code_stream, expected_instruction_name); 79 | 80 | std::vector info_stream; 81 | REQUIRE(decoder.DecodeInstructionStream(machine_code_stream, info_stream, msg)); 82 | REQUIRE(info_stream[0].bundle[0].instruction_name == expected_instruction_name); 83 | } 84 | -------------------------------------------------------------------------------- /test/source/test_decode_text.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | #include "amdisa_tests.h" 5 | #include "amdisa/isa_decoder.h" 6 | #include "catch.hpp" 7 | 8 | TEST_CASE("Test to fail decode of a shader disassembly text", "[decode][text][fail]") 9 | { 10 | amdisa::IsaDecoder decoder; 11 | std::string msg; 12 | TestConfig& config = TestConfig::getInstance(); 13 | REQUIRE(decoder.Initialize(config.GetXmlPath(), msg)); 14 | 15 | std::vector info; 16 | REQUIRE(decoder.DecodeShaderDisassemblyText("", info, msg, false) == false); 17 | } 18 | 19 | TEST_CASE("Test to decode of a shader disassembly text", "[decode][text]") 20 | { 21 | amdisa::IsaDecoder decoder; 22 | std::string msg; 23 | TestConfig& config = TestConfig::getInstance(); 24 | REQUIRE(decoder.Initialize(config.GetXmlPath(), msg)); 25 | 26 | std::vector info; 27 | REQUIRE(decoder.DecodeShaderDisassemblyText("s_cmp_eq_u32 s9, 0 // 000000000000: BF068009", info, msg, false)); 28 | REQUIRE(info[0].bundle[0].instruction_name == "S_CMP_EQ_U32"); 29 | } 30 | 31 | TEST_CASE("Test to fail decode of a shader disassembly file", "[decode][file][fail]") 32 | { 33 | amdisa::IsaDecoder decoder; 34 | std::string msg; 35 | TestConfig& config = TestConfig::getInstance(); 36 | REQUIRE(decoder.Initialize(config.GetXmlPath(), msg)); 37 | 38 | std::vector info; 39 | REQUIRE(decoder.DecodeShaderDisassemblyFile("./invalid_disassembly_file.sp3", info, msg, false) == false); 40 | } 41 | -------------------------------------------------------------------------------- /test/source/test_initialize.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. 3 | */ 4 | #include "amdisa_tests.h" 5 | #include "amdisa/isa_decoder.h" 6 | #include "catch.hpp" 7 | 8 | TEST_CASE("Perform Initialization with an invalid path", "[initialize][fail]") 9 | { 10 | amdisa::IsaDecoder decoder; 11 | std::string msg; 12 | REQUIRE(decoder.Initialize("./invalid_path.xml", msg) == false); 13 | } 14 | 15 | TEST_CASE("Perform Initialization with an user specified amdisa spec file", "[initialize]") 16 | { 17 | amdisa::IsaDecoder decoder; 18 | std::string msg; 19 | TestConfig& config = TestConfig::getInstance(); 20 | REQUIRE(decoder.Initialize(config.GetXmlPath(), msg)); 21 | } 22 | --------------------------------------------------------------------------------