├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── README.md ├── include └── Intriman │ ├── Generators │ ├── GeneratorFactory.hpp │ ├── GeneratorList.hpp │ └── IGenerator.hpp │ ├── Intriman.hpp │ ├── Intrinsic.hpp │ └── Settings.hpp ├── media ├── manpage.png ├── markdown.png └── plaintext.png └── source └── Intriman ├── Generators ├── Markdown.cpp ├── Roff.cpp └── Text.cpp ├── Intriman.cpp ├── Settings.cpp └── main.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /.vs -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "dependencies/pugixml"] 2 | path = dependencies/pugixml 3 | url = https://github.com/zeux/pugixml.git 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required( VERSION 3.2.2 ) 2 | project( Intriman ) 3 | 4 | ### Standard 5 | set( CMAKE_CXX_STANDARD 17 ) 6 | set( CMAKE_CXX_STANDARD_REQUIRED ON ) 7 | set( CMAKE_CXX_EXTENSIONS OFF ) 8 | 9 | ### Verbosity 10 | set( CMAKE_COLOR_MAKEFILE ON ) 11 | set( CMAKE_VERBOSE_MAKEFILE ON ) 12 | set( CMAKE_EXPORT_COMPILE_COMMANDS ON ) 13 | 14 | ### Optimizations 15 | if( MSVC ) 16 | add_compile_options( /W3 ) 17 | elseif( CMAKE_COMPILER_IS_GNUCXX ) 18 | add_compile_options( -m64 ) 19 | add_compile_options( -march=native ) 20 | add_compile_options( -Ofast ) 21 | add_compile_options( -Wall ) 22 | add_compile_options( -Wextra ) 23 | endif() 24 | 25 | ### Targets 26 | add_executable( 27 | Intriman 28 | source/Intriman/main.cpp 29 | source/Intriman/Intriman.cpp 30 | source/Intriman/Settings.cpp 31 | source/Intriman/Generators/Text.cpp 32 | source/Intriman/Generators/Roff.cpp 33 | source/Intriman/Generators/Markdown.cpp 34 | 35 | ### pugixml 36 | dependencies/pugixml/src/pugiconfig.hpp 37 | dependencies/pugixml/src/pugixml.hpp 38 | dependencies/pugixml/src/pugixml.cpp 39 | ) 40 | 41 | if( MSVC ) 42 | 43 | elseif( CMAKE_COMPILER_IS_GNUCXX ) 44 | target_link_libraries( 45 | Intriman 46 | stdc++fs 47 | ) 48 | endif() 49 | 50 | target_include_directories( 51 | Intriman 52 | PRIVATE 53 | include 54 | dependencies/pugixml/src 55 | ) 56 | 57 | ### Download data-latest.xml listing 58 | message( 59 | STATUS "Downloading data-latest.xml from intel..." 60 | ) 61 | file( 62 | DOWNLOAD 63 | "https://software.intel.com/sites/landingpage/IntrinsicsGuide/files/data-latest.xml" 64 | "./data-latest.xml" 65 | SHOW_PROGRESS 66 | ) 67 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Wunkolo 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Intriman [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) 2 | 3 | Intriman is a documentation generator that retargets the [Intel Intrinsics Guide](https://software.intel.com/sites/landingpage/IntrinsicsGuide/) data into additional **offline** documentation formats. 4 | 5 | --- 6 | 7 | Man page(groff): 8 | 9 | ![](media/manpage.png) 10 | 11 | Markdown: 12 | 13 | ![](media/markdown.png) 14 | 15 | Plaintext: 16 | 17 | ![](media/plaintext.png) 18 | 19 | --- 20 | 21 | ## Dependencies 22 | 23 | * [Cmake 3.2.2+](https://www.cmake.org/download/) 24 | * [pugixml](https://github.com/zeux/pugixml) 25 | 26 | ## Building 27 | 28 | Clone the repository with submodules: 29 | 30 | `git clone --recursive https://github.com/Wunkolo/Intriman.git` 31 | 32 | ### Windows 33 | 34 | Using Visual Studio 2017, simply open `CMakeLists.txt` using Visual Studios [built-in support for opening CMake projects](https://blogs.msdn.microsoft.com/vcblog/2016/10/05/cmake-support-in-visual-studio/): 35 | 36 | ![](https://i.imgur.com/NmnwidH.png) 37 | 38 | Finally, select your desired build target and architecture and then build. Compiled binaries will be found in the cache folder: 39 | 40 | ![](https://i.imgur.com/binVwSK.png) 41 | 42 | ![](https://i.imgur.com/Ad0KG7t.png) 43 | 44 | ![](https://i.imgur.com/Lyqmwbi.png) 45 | 46 | ### Linux 47 | 48 | Typical [Cmake out-of-source build procedure](http://preshing.com/20170511/how-to-build-a-cmake-based-project/#running-cmake-from-the-command-line): 49 | 50 | ``` 51 | cd Intriman 52 | mkdir build 53 | cd build 54 | cmake .. 55 | make 56 | ``` 57 | 58 | ## Usage 59 | 60 | CMake generation should automatically download `data-latest.xml` from Intel. 61 | Otherwise, download the file from `https://software.intel.com/sites/landingpage/IntrinsicsGuide/files/data-latest.xml` and simply drag and drop this file onto the executable, or put `data-latest.xml` as the first argument(`Intriman data-latest.xml`), and the documentation files will be generated( default output directory is `./docs/` relative to the executable path ) 62 | 63 | ![](https://i.imgur.com/YwGg9y0.png) 64 | 65 | ![](https://i.imgur.com/OOE9HrB.gif) 66 | 67 | ![](https://i.imgur.com/fa1bm4M.gif) 68 | -------------------------------------------------------------------------------- /include/Intriman/Generators/GeneratorFactory.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "IGenerator.hpp" 6 | #include "../Settings.hpp" 7 | 8 | namespace Intriman 9 | { 10 | namespace GeneratorFactory 11 | { 12 | /// Creates a "Create(GeneratorName)Generator(); for every Generator 13 | #undef GEN_ENTRY 14 | #define GEN_ENTRY(GEN_NAME) \ 15 | extern std::unique_ptr Create##GEN_NAME##Generator(const Settings& Settings); 16 | 17 | #include "GeneratorList.hpp" 18 | #undef GEN_ENTRY 19 | 20 | /// Creates an "e(GeneratorName)" enum for every Generator 21 | enum class GeneratorID : std::size_t 22 | { 23 | #undef GEN_ENTRY 24 | #define GEN_ENTRY(GEN_NAME) e##GEN_NAME, 25 | 26 | #include "GeneratorList.hpp" 27 | #undef GEN_ENTRY 28 | }; 29 | 30 | /// Creates a "(GeneratorName)" string for every Generator 31 | static const char* GeneratorNames[] = 32 | { 33 | #undef GEN_ENTRY 34 | #define GEN_ENTRY(GEN_NAME) #GEN_NAME, 35 | 36 | #include "GeneratorList.hpp" 37 | #undef GEN_ENTRY 38 | }; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /include/Intriman/Generators/GeneratorList.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Usage: 3 | * #undef GEN_ENTRY 4 | * #define GEN_ENTRY(GEN_NAME) \ 5 | * // stuff you want to do per-GEN-entry 6 | * // use "##GEN_NAME##" 7 | * // ex: SomeVectorOfGenerators.push_back("##GEN_NAME##"); 8 | * 9 | * #include "Generators.hpp" 10 | * #undef GEN_ENTRY 11 | */ 12 | 13 | GEN_ENTRY(Text) 14 | GEN_ENTRY(Roff) 15 | GEN_ENTRY(Markdown) -------------------------------------------------------------------------------- /include/Intriman/Generators/IGenerator.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include "../Intrinsic.hpp" 3 | 4 | namespace Intriman 5 | { 6 | class IGenerator 7 | { 8 | public: 9 | IGenerator() 10 | { 11 | } 12 | 13 | virtual ~IGenerator() 14 | { 15 | } 16 | 17 | virtual void StartList(const char* Version, const char* Date) 18 | { 19 | } 20 | 21 | virtual void VisitIntrinsic(const Intrinsic& CurIntrin) 22 | { 23 | } 24 | 25 | virtual void EndList() 26 | { 27 | } 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /include/Intriman/Intriman.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "Intrinsic.hpp" 8 | #include "Generators/GeneratorFactory.hpp" 9 | 10 | namespace Intriman 11 | { 12 | bool ProcessFile( 13 | std::istream& Stream, 14 | const std::vector>& Visitor 15 | ); 16 | } -------------------------------------------------------------------------------- /include/Intriman/Intrinsic.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | #include 5 | 6 | namespace Intriman 7 | { 8 | struct Intrinsic 9 | { 10 | const char* Name; 11 | const char* ReturnType; 12 | const char* Technology; 13 | 14 | const char* Type; 15 | const char* Category; 16 | std::vector CPUID; 17 | 18 | struct Parameter 19 | { 20 | const char* Name; 21 | const char* Type; 22 | }; 23 | 24 | std::vector Parameters; 25 | 26 | const char* Description; 27 | const char* Operation; 28 | 29 | const char* Header; 30 | 31 | struct Instruction 32 | { 33 | const char* Name; 34 | const char* Form; 35 | }; 36 | 37 | std::vector Instructions; 38 | }; 39 | } -------------------------------------------------------------------------------- /include/Intriman/Settings.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | namespace Intriman 5 | { 6 | struct Settings 7 | { 8 | Settings(); 9 | std::experimental::filesystem::path OutputFolder; 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /media/manpage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wunkolo/Intriman/15c326b62784dd30e67365790bf33d600055a773/media/manpage.png -------------------------------------------------------------------------------- /media/markdown.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wunkolo/Intriman/15c326b62784dd30e67365790bf33d600055a773/media/markdown.png -------------------------------------------------------------------------------- /media/plaintext.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Wunkolo/Intriman/15c326b62784dd30e67365790bf33d600055a773/media/plaintext.png -------------------------------------------------------------------------------- /source/Intriman/Generators/Markdown.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | namespace fs = std::experimental::filesystem; 16 | 17 | class MarkdownGenerator : public Intriman::IGenerator 18 | { 19 | public: 20 | explicit MarkdownGenerator(const std::experimental::filesystem::path& Folder); 21 | 22 | virtual ~MarkdownGenerator() override; 23 | 24 | virtual void StartList(const char* Version, const char* Date) override; 25 | 26 | virtual void VisitIntrinsic(const Intriman::Intrinsic& CurIntrin) override; 27 | 28 | virtual void EndList() override; 29 | 30 | private: 31 | 32 | fs::path CurPath; 33 | std::unordered_map Subfiles; 34 | std::ofstream Index; 35 | }; 36 | 37 | 38 | MarkdownGenerator::MarkdownGenerator(const fs::path& Folder) 39 | { 40 | CurPath = Folder / "markdown"; 41 | fs::create_directories(CurPath); 42 | Index.open( 43 | (CurPath / "Index.md") 44 | ); 45 | 46 | Index 47 | << "Intriman\n===\n\n"; 48 | } 49 | 50 | MarkdownGenerator::~MarkdownGenerator() 51 | { 52 | for( auto& SubFile : Subfiles ) 53 | { 54 | SubFile.second.close(); 55 | } 56 | Index.close(); 57 | } 58 | 59 | void MarkdownGenerator::StartList(const char* Version, const char* Date) 60 | { 61 | Index 62 | << "```\n" 63 | << "Version: " << Version << '\n' 64 | << "Date: " << Date << '\n' 65 | << "```\n---\n"; 66 | } 67 | 68 | void MarkdownGenerator::VisitIntrinsic(const Intriman::Intrinsic& CurIntrin) 69 | { 70 | // New technology detected 71 | if( !Subfiles.count(CurIntrin.Technology) ) 72 | { 73 | std::string TechName(CurIntrin.Technology); 74 | // All non-alphanum characters are converted to '-' 75 | std::replace_if( 76 | TechName.begin(), 77 | TechName.end(), 78 | [](char c) 79 | { 80 | return !std::isalnum(c); 81 | }, 82 | '-' 83 | ); 84 | 85 | const fs::path Path = (CurPath / TechName).replace_extension(".md"); 86 | // New file for technology 87 | Subfiles[CurIntrin.Technology] = std::ofstream( 88 | Path 89 | ); 90 | 91 | // Header for new file 92 | Subfiles[CurIntrin.Technology] 93 | << CurIntrin.Technology 94 | << "\n===\n\n"; 95 | 96 | 97 | Index 98 | << "### " 99 | << '[' << CurIntrin.Technology << "](" << "./" << TechName << ".md)" 100 | << "\n"; 101 | } 102 | std::ostream& Stream = Subfiles[CurIntrin.Technology]; 103 | 104 | std::size_t i = 0; 105 | 106 | // Header 107 | Stream 108 | << "## " << CurIntrin.Name 109 | << "\n\n"; 110 | 111 | // Intrinsic 112 | Stream 113 | << "```cpp\n"; 114 | 115 | if( CurIntrin.Header != nullptr ) 116 | { 117 | Stream 118 | << "#include <" 119 | << CurIntrin.Header 120 | << ">\n\n"; 121 | } 122 | 123 | Stream << CurIntrin.ReturnType << ' ' 124 | << CurIntrin.Name << '(' 125 | << "\n"; 126 | i = 0; 127 | for( const auto& CurParam : CurIntrin.Parameters ) 128 | { 129 | Stream 130 | << ' ' 131 | << CurParam.Type 132 | << ' ' 133 | << CurParam.Name 134 | << (i == CurIntrin.Parameters.size() - 1 ? ' ' : ',') 135 | << '\n'; 136 | ++i; 137 | } 138 | Stream 139 | << ");\n```\n\n"; 140 | 141 | // Description 142 | if( CurIntrin.Description != nullptr ) 143 | { 144 | Stream 145 | //<< "Description:\n" 146 | << '>' 147 | << CurIntrin.Description 148 | << "\n\n"; 149 | } 150 | 151 | // Operation 152 | if( CurIntrin.Operation != nullptr ) 153 | { 154 | Stream 155 | << "```" 156 | << CurIntrin.Operation 157 | << "\n```\n\n"; 158 | } 159 | 160 | // CPUID 161 | if( CurIntrin.CPUID.size() ) 162 | { 163 | Stream 164 | << "CPUID:"; 165 | i = 0; 166 | for( const auto& CurCPUID : CurIntrin.CPUID ) 167 | { 168 | Stream 169 | << " `" << CurCPUID << '`' 170 | << (i == CurIntrin.CPUID.size() - 1 ? ' ' : ','); 171 | ++i; 172 | } 173 | Stream 174 | << "\n\n"; 175 | } 176 | 177 | // Instructions 178 | if( CurIntrin.Instructions.size() ) 179 | { 180 | Stream 181 | << "Instruction|Arguments\n" 182 | << "-|-\n"; 183 | for( const auto& CurInstruction : CurIntrin.Instructions ) 184 | { 185 | Stream 186 | << CurInstruction.Name 187 | << '|' 188 | << CurInstruction.Form 189 | << '\n'; 190 | } 191 | } 192 | 193 | Stream 194 | << "\n---\n"; 195 | } 196 | 197 | void MarkdownGenerator::EndList() 198 | { 199 | } 200 | 201 | 202 | std::unique_ptr Intriman::GeneratorFactory::CreateMarkdownGenerator( 203 | const Settings& Settings 204 | ) 205 | { 206 | return std::make_unique(Settings.OutputFolder); 207 | } 208 | -------------------------------------------------------------------------------- /source/Intriman/Generators/Roff.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | namespace fs = std::experimental::filesystem; 17 | 18 | class RoffGenerator : public Intriman::IGenerator 19 | { 20 | public: 21 | explicit RoffGenerator(const std::experimental::filesystem::path& Folder); 22 | 23 | virtual ~RoffGenerator() override; 24 | 25 | virtual void StartList(const char* Version, const char* Date) override; 26 | 27 | virtual void VisitIntrinsic(const Intriman::Intrinsic& CurIntrin) override; 28 | 29 | virtual void EndList() override; 30 | 31 | private: 32 | std::string Version; 33 | std::string Date; 34 | fs::path CurPath; 35 | std::unordered_map SubFolders; 36 | }; 37 | 38 | 39 | RoffGenerator::RoffGenerator(const fs::path& Folder) 40 | { 41 | CurPath = Folder / "roff"; 42 | fs::create_directories(CurPath); 43 | } 44 | 45 | RoffGenerator::~RoffGenerator() 46 | { 47 | } 48 | 49 | void RoffGenerator::StartList(const char* Version, const char* Date) 50 | { 51 | this->Version = Version; 52 | this->Date = Date; 53 | } 54 | 55 | void RoffGenerator::VisitIntrinsic(const Intriman::Intrinsic& CurIntrin) 56 | { 57 | // New technology detected 58 | if( !SubFolders.count(CurIntrin.Technology) ) 59 | { 60 | std::string TechName(CurIntrin.Technology); 61 | // All non-alphanum characters are converted to '-' 62 | std::replace_if( 63 | TechName.begin(), 64 | TechName.end(), 65 | [](char c) 66 | { 67 | return !std::isalnum(c); 68 | }, 69 | '-' 70 | ); 71 | 72 | const fs::path Path = (CurPath / TechName); 73 | fs::create_directories(Path); 74 | // New subfolder for technology 75 | SubFolders[CurIntrin.Technology] = Path; 76 | } 77 | 78 | // New file for instruction 79 | const fs::path FilePath = SubFolders[CurIntrin.Technology] / CurIntrin.Name; 80 | std::ofstream Stream( 81 | FilePath 82 | ); 83 | 84 | std::size_t i = 0; 85 | 86 | // Header 87 | Stream 88 | << ".TH " 89 | << CurIntrin.Name 90 | << " 3 " 91 | << Date 92 | << " \"" 93 | << CurIntrin.Technology 94 | << " Intrinsics\" \n"; 95 | 96 | Stream 97 | << ".SH NAME\n" 98 | << CurIntrin.Name 99 | << '\n'; 100 | 101 | // Syntax 102 | Stream 103 | << ".SH SYNTAX\n" 104 | << "\\f[B]#include <\\f[]" 105 | << "\\f[I]" 106 | << CurIntrin.Header 107 | << "\\f[]\\f[B]>\\f[]\n.sp\n.sp\n"; 108 | 109 | Stream 110 | << CurIntrin.ReturnType 111 | << " \\f[B]" << CurIntrin.Name << "\\f[]( "; 112 | 113 | i = 0; 114 | if( CurIntrin.Parameters.size() > 3 ) 115 | { 116 | Stream << "\n.br\n"; 117 | for( const auto& CurParam : CurIntrin.Parameters ) 118 | { 119 | Stream << '\t' << CurParam.Type; 120 | 121 | if( CurParam.Name != nullptr ) 122 | { 123 | Stream 124 | << "\t\\f[I]" << CurParam.Name << "\\f[]"; 125 | } 126 | Stream 127 | << (i == CurIntrin.Parameters.size() - 1 ? "\n.br\n" : ",\n.br\n"); 128 | ++i; 129 | } 130 | } 131 | else 132 | { 133 | for( const auto& CurParam : CurIntrin.Parameters ) 134 | { 135 | Stream 136 | << CurParam.Type; 137 | 138 | if( CurParam.Name != nullptr ) 139 | { 140 | Stream 141 | << " \\f[I]" << CurParam.Name << "\\f[]"; 142 | } 143 | Stream 144 | << (i == CurIntrin.Parameters.size() - 1 ? "" : ", "); 145 | ++i; 146 | } 147 | } 148 | Stream << ");\n"; 149 | 150 | // Description 151 | if( CurIntrin.Description != nullptr ) 152 | { 153 | Stream 154 | << ".SH DESCRIPTION\n" 155 | << CurIntrin.Description 156 | << '\n'; 157 | } 158 | 159 | // Operation 160 | if( CurIntrin.Operation != nullptr ) 161 | { 162 | std::string Pseudo(CurIntrin.Operation); 163 | Pseudo = std::regex_replace( 164 | Pseudo, 165 | std::regex("\n"), 166 | "\n.br\n" 167 | ); 168 | Stream 169 | << ".SH OPERATION\n" 170 | << Pseudo 171 | << '\n'; 172 | } 173 | 174 | // CPUID 175 | if( CurIntrin.CPUID.size() ) 176 | { 177 | Stream 178 | << ".SH CPUID\n"; 179 | i = 0; 180 | for( const auto& CurCPUID : CurIntrin.CPUID ) 181 | { 182 | Stream 183 | << "\\f[I]" 184 | << CurCPUID 185 | << "\\f[]" 186 | << (i == CurIntrin.CPUID.size() - 1 ? ' ' : ','); 187 | ++i; 188 | } 189 | Stream << '\n'; 190 | } 191 | 192 | // Instructions 193 | if( CurIntrin.Instructions.size() ) 194 | { 195 | Stream 196 | << ".SH ASSEMBLY\n" 197 | << ".TS\nALLBOX;\nl c.\n" 198 | << "\\f[B]Instruction\tOperands\\f[]\n"; 199 | for( const auto& CurInstruction : CurIntrin.Instructions ) 200 | { 201 | Stream 202 | << "\\f[I]" 203 | << CurInstruction.Name 204 | << '\t' 205 | << CurInstruction.Form 206 | << "\\f[]\n"; 207 | } 208 | Stream << ".TE\n"; 209 | } 210 | } 211 | 212 | void RoffGenerator::EndList() 213 | { 214 | } 215 | 216 | 217 | std::unique_ptr Intriman::GeneratorFactory::CreateRoffGenerator( 218 | const Settings& Settings 219 | ) 220 | { 221 | return std::make_unique(Settings.OutputFolder); 222 | } 223 | -------------------------------------------------------------------------------- /source/Intriman/Generators/Text.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | namespace fs = std::experimental::filesystem; 16 | 17 | std::vector Wrap(const std::string& String, std::size_t MaxLength) 18 | { 19 | std::stringstream Stream; 20 | Stream << String; 21 | 22 | std::vector Lines; 23 | while( Stream.good() ) // Copy all lines into string 24 | { 25 | std::string CurLine; 26 | std::getline(Stream, CurLine); 27 | Lines.push_back(CurLine); 28 | } 29 | 30 | std::vector SplitString; 31 | 32 | for( std::size_t i = 0; i < Lines.size(); ++i ) 33 | { 34 | std::string CurLine(Lines[i]); 35 | while( CurLine.length() > MaxLength ) 36 | { 37 | std::size_t EndIndex = MaxLength; 38 | while( EndIndex > 0 && !std::isspace(CurLine[EndIndex]) ) 39 | { 40 | --EndIndex; 41 | } 42 | if( EndIndex <= 0 ) 43 | { 44 | EndIndex = MaxLength; 45 | } 46 | 47 | SplitString.push_back(CurLine.substr(0, EndIndex)); 48 | CurLine = CurLine.substr(EndIndex + 1, std::string::npos); 49 | } 50 | 51 | SplitString.push_back(CurLine); 52 | } 53 | 54 | return SplitString; 55 | } 56 | 57 | class TextGenerator : public Intriman::IGenerator 58 | { 59 | public: 60 | explicit TextGenerator(const std::experimental::filesystem::path& Folder); 61 | 62 | virtual ~TextGenerator() override; 63 | 64 | virtual void StartList(const char* Version, const char* Date) override; 65 | 66 | virtual void VisitIntrinsic(const Intriman::Intrinsic& CurIntrin) override; 67 | 68 | virtual void EndList() override; 69 | 70 | private: 71 | 72 | fs::path CurPath; 73 | std::unordered_map Subfiles; 74 | std::ofstream Index; 75 | }; 76 | 77 | 78 | TextGenerator::TextGenerator(const fs::path& Folder) 79 | { 80 | CurPath = Folder / "text"; 81 | fs::create_directories(CurPath); 82 | Index.open( 83 | (CurPath / "Index.txt") 84 | ); 85 | 86 | Index 87 | << "Intriman\n===\n\n"; 88 | } 89 | 90 | TextGenerator::~TextGenerator() 91 | { 92 | for( auto& SubFile : Subfiles ) 93 | { 94 | SubFile.second.close(); 95 | } 96 | Index.close(); 97 | } 98 | 99 | void TextGenerator::StartList(const char* Version, const char* Date) 100 | { 101 | Index 102 | << "```\n" 103 | << "Version: " << Version << '\n' 104 | << "Date: " << Date << '\n' 105 | << "```\n---\n"; 106 | } 107 | 108 | void TextGenerator::VisitIntrinsic(const Intriman::Intrinsic& CurIntrin) 109 | { 110 | // New technology detected 111 | if( !Subfiles.count(CurIntrin.Technology) ) 112 | { 113 | std::string TechName(CurIntrin.Technology); 114 | // All non-alphanum characters are converted to '-' 115 | std::replace_if( 116 | TechName.begin(), 117 | TechName.end(), 118 | [](char c) 119 | { 120 | return !std::isalnum(c); 121 | }, 122 | '-' 123 | ); 124 | 125 | const fs::path Path = (CurPath / TechName).replace_extension(".txt"); 126 | // New file for technology 127 | Subfiles[CurIntrin.Technology] = std::ofstream( 128 | Path 129 | ); 130 | 131 | // Header for new file 132 | Subfiles[CurIntrin.Technology] 133 | << CurIntrin.Technology 134 | << "\n\n"; 135 | 136 | Index 137 | << CurIntrin.Technology << '-' 138 | << '\n'; 139 | } 140 | std::ostream& Stream = Subfiles[CurIntrin.Technology]; 141 | 142 | std::size_t i = 0; 143 | 144 | // Header 145 | Stream 146 | << "\n\n" 147 | << std::string(80, '-') 148 | << "\n\n" 149 | << "- " << CurIntrin.Name 150 | << "\n\n"; 151 | 152 | // Intrinsic 153 | if( CurIntrin.Header != nullptr ) 154 | { 155 | Stream 156 | << "#include <" 157 | << CurIntrin.Header 158 | << ">\n\n"; 159 | } 160 | 161 | Stream << CurIntrin.ReturnType << ' ' 162 | << CurIntrin.Name << '(' 163 | << "\n"; 164 | i = 0; 165 | for( const auto& CurParam : CurIntrin.Parameters ) 166 | { 167 | Stream 168 | << '\t' 169 | << CurParam.Type 170 | << ' ' 171 | << CurParam.Name 172 | << (i == CurIntrin.Parameters.size() - 1 ? ' ' : ',') 173 | << '\n'; 174 | ++i; 175 | } 176 | Stream 177 | << ");\n\n"; 178 | 179 | // Description 180 | if( CurIntrin.Description != nullptr ) 181 | { 182 | const std::vector SplitDescription = Wrap( 183 | CurIntrin.Description, 184 | 80 185 | ); 186 | 187 | for( const auto& CurLine : SplitDescription ) 188 | { 189 | Stream 190 | << CurLine 191 | << '\n'; 192 | } 193 | } 194 | 195 | // Operation 196 | if( CurIntrin.Operation != nullptr ) 197 | { 198 | Stream 199 | << CurIntrin.Operation 200 | << '\n'; 201 | } 202 | 203 | // CPUID 204 | if( CurIntrin.CPUID.size() ) 205 | { 206 | Stream 207 | << "CPUID: "; 208 | i = 0; 209 | for( const auto& CurCPUID : CurIntrin.CPUID ) 210 | { 211 | Stream 212 | << CurCPUID 213 | << (i == CurIntrin.CPUID.size() - 1 ? ' ' : ','); 214 | ++i; 215 | } 216 | Stream 217 | << "\n\n"; 218 | } 219 | 220 | // Instructions 221 | if( CurIntrin.Instructions.size() ) 222 | { 223 | Stream 224 | << std::setw(16) << std::left << "Instruction" 225 | << std::setw(16) << "Operands" 226 | << '\n' 227 | << std::string(32, '-') 228 | << '\n'; 229 | for( const auto& CurInstruction : CurIntrin.Instructions ) 230 | { 231 | Stream 232 | << std::setw(16) << std::left << CurInstruction.Name 233 | << std::setw(16) << CurInstruction.Form 234 | << '\n'; 235 | } 236 | } 237 | } 238 | 239 | void TextGenerator::EndList() 240 | { 241 | } 242 | 243 | 244 | std::unique_ptr Intriman::GeneratorFactory::CreateTextGenerator( 245 | const Settings& Settings 246 | ) 247 | { 248 | return std::make_unique(Settings.OutputFolder); 249 | } 250 | -------------------------------------------------------------------------------- /source/Intriman/Intriman.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | 9 | namespace Intriman 10 | { 11 | 12 | bool ProcessFile( 13 | std::istream& Stream, 14 | const std::vector>& Generators 15 | ) 16 | { 17 | pugi::xml_document Document; 18 | const pugi::xml_parse_result Parse = Document.load(Stream); 19 | 20 | if( Parse.status != pugi::xml_parse_status::status_ok ) 21 | { 22 | // Error parsing 23 | return false; 24 | } 25 | 26 | const pugi::xml_node IntrinsicsList = Document.first_child(); 27 | 28 | for( auto& CurGenerator : Generators ) 29 | { 30 | CurGenerator->StartList( 31 | IntrinsicsList.attribute("version").value(), 32 | IntrinsicsList.attribute("date").value() 33 | ); 34 | } 35 | 36 | std::size_t CurIndex = 0; 37 | const std::size_t LastIndex = std::distance( 38 | Document.first_child().children().begin(), 39 | Document.first_child().children().end() 40 | ) - 1; 41 | 42 | for( const pugi::xml_node& IntrinsicXML : Document.first_child().children() ) 43 | { 44 | Intriman::Intrinsic CurIntrinsic; 45 | CurIntrinsic.Name = IntrinsicXML.attribute("name").value(); 46 | CurIntrinsic.ReturnType = IntrinsicXML.attribute("rettype").value(); 47 | CurIntrinsic.Technology = IntrinsicXML.attribute("tech").value(); 48 | 49 | CurIntrinsic.Type = IntrinsicXML.child("type").child_value(); 50 | CurIntrinsic.Category = IntrinsicXML.child("category").child_value(); 51 | // CPUID 52 | for( pugi::xml_node CurCPUID = IntrinsicXML.child("CPUID"); 53 | CurCPUID; 54 | CurCPUID = CurCPUID.next_sibling("CPUID") 55 | ) 56 | { 57 | CurIntrinsic.CPUID.push_back(CurCPUID.text().get()); 58 | } 59 | 60 | CurIntrinsic.Description = IntrinsicXML.child("description").child_value(); 61 | CurIntrinsic.Operation = IntrinsicXML.child("operation").child_value(); 62 | CurIntrinsic.Header = IntrinsicXML.child("header").child_value(); 63 | 64 | // Parameters 65 | for( pugi::xml_node CurParam = IntrinsicXML.child("parameter"); 66 | CurParam; 67 | CurParam = CurParam.next_sibling("parameter") 68 | ) 69 | { 70 | Intriman::Intrinsic::Parameter NewParam; 71 | NewParam.Name = CurParam.attribute("varname").value(); 72 | NewParam.Type = CurParam.attribute("type").value(); 73 | CurIntrinsic.Parameters.push_back(NewParam); 74 | } 75 | 76 | // Instruction 77 | for( pugi::xml_node CurInstru = IntrinsicXML.child("instruction"); 78 | CurInstru; 79 | CurInstru = CurInstru.next_sibling("instruction") ) 80 | { 81 | Intriman::Intrinsic::Instruction NewInstruc; 82 | NewInstruc.Name = CurInstru.attribute("name").value(); 83 | NewInstruc.Form = CurInstru.attribute("form").value(); 84 | CurIntrinsic.Instructions.push_back(NewInstruc); 85 | } 86 | for( auto& CurGenerator : Generators ) 87 | { 88 | CurGenerator->VisitIntrinsic(CurIntrinsic); 89 | } 90 | 91 | CurIndex++; 92 | std::printf( 93 | "Processing instruction: %8zu/%8zu %%%5.2f%c", 94 | CurIndex, 95 | LastIndex, 96 | (CurIndex / static_cast(LastIndex)) * 100.0f, 97 | CurIndex == LastIndex ? '\n':'\r' 98 | ); 99 | std::fflush(stdout); 100 | } 101 | 102 | for( auto& CurGenerator : Generators ) 103 | { 104 | CurGenerator->EndList(); 105 | } 106 | 107 | return true; 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /source/Intriman/Settings.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | Intriman::Settings::Settings() 4 | { 5 | // Default settings 6 | OutputFolder = "./docs/"; 7 | } 8 | -------------------------------------------------------------------------------- /source/Intriman/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | namespace fs = std::experimental::filesystem; 9 | 10 | #include 11 | 12 | void PrintHelp() 13 | { 14 | std::puts("Intriman | Build Date: " __TIMESTAMP__); 15 | std::puts( 16 | "Generates alternative documentation formats from the intel intrinsics" 17 | "database." 18 | ); 19 | std::puts("\t - Wunkolo "); 20 | std::puts("Available Generators:"); 21 | #undef GEN_ENTRY 22 | #define GEN_ENTRY(GEN_NAME) std::puts("\t - " #GEN_NAME); 23 | #include 24 | #undef GEN_ENTRY 25 | } 26 | 27 | int main(int argc, const char* argv[]) 28 | { 29 | if( argc < 2 ) 30 | { 31 | PrintHelp(); 32 | return EXIT_FAILURE; 33 | } 34 | 35 | std::ifstream InputFile(argv[1]); 36 | 37 | if( !InputFile ) 38 | { 39 | std::printf( 40 | "Error opening file: %s", 41 | argv[1] 42 | ); 43 | return EXIT_FAILURE; 44 | } 45 | 46 | const Intriman::Settings CurSettings; 47 | 48 | std::vector> Generators; 49 | 50 | #undef GEN_ENTRY 51 | #define GEN_ENTRY(GEN_NAME) \ 52 | Generators.push_back( \ 53 | Intriman::GeneratorFactory::Create##GEN_NAME##Generator(CurSettings)\ 54 | ); 55 | #include 56 | #undef GEN_ENTRY 57 | 58 | return Intriman::ProcessFile(InputFile, Generators) ? EXIT_SUCCESS : EXIT_FAILURE; 59 | } 60 | --------------------------------------------------------------------------------