diff options
| author | Amlal El Mahrouss <amlal@nekernel.org> | 2025-12-05 11:49:28 -0500 |
|---|---|---|
| committer | Amlal El Mahrouss <amlal@nekernel.org> | 2025-12-05 11:50:39 -0500 |
| commit | 037ac38824623c13070384e8fc0e70c4770dcdbd (patch) | |
| tree | 19d7286c5d226b33f10743c76436dace0cf42112 /include | |
| parent | 5535f22998bf991eeb75a56c9e147f0fd4bd23b2 (diff) | |
chore! new project filesystem structure.
Signed-off-by: Amlal El Mahrouss <amlal@nekernel.org>
Diffstat (limited to 'include')
40 files changed, 6619 insertions, 0 deletions
diff --git a/include/CompilerKit/AE.h b/include/CompilerKit/AE.h new file mode 100644 index 0000000..cf6e71b --- /dev/null +++ b/include/CompilerKit/AE.h @@ -0,0 +1,138 @@ +/* + * ======================================================== + * + * CompilerKit + * Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. + * + * ======================================================== + */ + +#ifndef _NECTI_AE_H_ +#define _NECTI_AE_H_ + +#include <CompilerKit/Detail/Config.h> +#include <fstream> + +#define kAEIdentVersion (0x0122) + +#define kAEMag0 'A' +#define kAEMag1 'E' +#define kAEMag2 'F' + +#define kAESymbolLen (256) +#define kAEPad (8) +#define kAEMagLen (3) +#define kAENullType (0x00) + +/// @author Amlal El Mahrouss + +/// @brief +// Advanced Executable File Format for ld64. +// Reloctable by offset is the default strategy. +// You can also relocate at runtime but that's up to the operating system loader. + +namespace CompilerKit { +// @brief Advanced Executable Header +// One thing to keep in mind. +// This object format, is reloctable. +typedef struct AEHeader final { + Char fMagic[kAEMagLen] = {}; + UInt16 fVersion{kAEIdentVersion}; + Char fArch{}; + Char fSubArch{}; + SizeType fCount{}; + Char fSize{}; + SizeType fStartCode{}; + SizeType fCodeSize{}; + Char fPad[kAEPad] = {}; +} PACKED AEHeader, *AEHeaderPtr; + +// @brief Advanced Executable Record. +// Could be data, code or bss. +// fKind must be filled with PEF fields. + +typedef struct AERecordHeader final { + Char fName[kAESymbolLen]; + SizeType fKind; + SizeType fSize; + SizeType fFlags; + UIntPtr fOffset; + Char fPad[kAEPad]; +} PACKED AERecordHeader, *AERecordHeaderPtr; + +enum { + kKindRelocationByOffset = 0x23f, + kKindRelocationAtRuntime = 0x34f, +}; +} // namespace CompilerKit + +// provide operator<< for AE + +inline std::ofstream& operator<<(std::ofstream& fp, CompilerKit::AEHeader& container) { + fp.write((char*) &container, sizeof(CompilerKit::AEHeader)); + + return fp; +} + +inline std::ofstream& operator<<(std::ofstream& fp, CompilerKit::AERecordHeader& container) { + fp.write((char*) &container, sizeof(CompilerKit::AERecordHeader)); + + return fp; +} + +inline std::ifstream& operator>>(std::ifstream& fp, CompilerKit::AEHeader& container) { + fp.read((char*) &container, sizeof(CompilerKit::AEHeader)); + return fp; +} + +inline std::ifstream& operator>>(std::ifstream& fp, CompilerKit::AERecordHeader& container) { + fp.read((char*) &container, sizeof(CompilerKit::AERecordHeader)); + return fp; +} + +namespace CompilerKit::Utils { +/** + * @brief AE Reader protocol + * + */ +class AEReadableProtocol final { + public: + std::ifstream file_pointer_; + + public: + explicit AEReadableProtocol() = default; + ~AEReadableProtocol() = default; + + NECTI_COPY_DELETE(AEReadableProtocol); + + /** + * @brief Read AE Record headers. + * + * @param raw the containing buffer + * @param sz it's size (1 = one AERecordHeader, 2 two AERecordHeader(s)) + * @return AERecordHeaderPtr + */ + AERecordHeaderPtr Read(char* raw, std::size_t sz) { + if (!raw) return nullptr; + + return this->Read_<AERecordHeader>(raw, sz * sizeof(AERecordHeader)); + } + + private: + /** + * @brief Implementation of Read for raw classes. + * + * @tparam TypeClass The class to read. + * @param raw the buffer + * @param sz the size + * @return TypeClass* the returning class. + */ + template <typename TypeClass> + TypeClass* Read_(char* raw, std::size_t sz) { + file_pointer_.read(raw, std::streamsize(sz)); + return reinterpret_cast<TypeClass*>(raw); + } +}; +} // namespace CompilerKit::Utils + +#endif /* ifndef _NECTI_AE_H_ */
\ No newline at end of file diff --git a/include/CompilerKit/AST.h b/include/CompilerKit/AST.h new file mode 100644 index 0000000..3987f13 --- /dev/null +++ b/include/CompilerKit/AST.h @@ -0,0 +1,143 @@ +/* ======================================== + + Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license + +======================================== */ + +#pragma once + +#include <CompilerKit/CodeGenerator.h> +#include <vector> + +#define CK_COMPILER_FRONTEND : public ::CompilerKit::CompilerFrontendInterface + +namespace CompilerKit { +inline static auto kInvalidFrontend = "(null)"; + +struct SyntaxLeafList; +struct SyntaxLeafList; +struct CompilerKeyword; + +/// =========================================================== /// +/// @note we want to do that to separate keywords. +/// =========================================================== /// + +enum KeywordKind { + kKeywordKindReserved = 0, + kKeywordKindNamespace = 100, + kKeywordKindFunctionStart, + kKeywordKindFunctionEnd, + kKeywordKindVariable, + kKeywordKindVariablePtr, + kKeywordKindType, + kKeywordKindTypePtr, + kKeywordKindExpressionBegin, + kKeywordKindExpressionEnd, + kKeywordKindArgSeparator, + kKeywordKindBodyStart, + kKeywordKindBodyEnd, + kKeywordKindClass, + kKeywordKindPtrAccess, + kKeywordKindAccess, + kKeywordKindIf, + kKeywordKindElse, + kKeywordKindElseIf, + kKeywordKindVariableAssign, + kKeywordKindVariableDec, + kKeywordKindVariableInc, + kKeywordKindConstant, + kKeywordKindTypedef, + kKeywordKindEndInstr, + kKeywordKindSpecifier, + kKeywordKindInvalid, + kKeywordKindReturn, + kKeywordKindCommentInline, + kKeywordKindCommentMultiLineStart, + kKeywordKindCommentMultiLineEnd, + kKeywordKindEq, + kKeywordKindNotEq, + kKeywordKindGreaterEq, + kKeywordKindLessEq, + kKeywordKindPtr, + kKeywordKindCount = kKeywordKindPtr - kKeywordKindNamespace + 1, +}; + +/// =========================================================== /// +/// \brief Compiler keyword information struct. +/// =========================================================== /// +struct CompilerKeyword { + CompilerKeyword(STLString name, KeywordKind kind) : keyword_name(name), keyword_kind(kind) {} + + STLString keyword_name{""}; + KeywordKind keyword_kind{kKeywordKindInvalid}; +}; + +struct SyntaxLeafList final { + struct SyntaxLeaf final { + Int32 fUserType{0U}; + CompilerKeyword fUserData{"", kKeywordKindInvalid}; + + STLString fUserValue{""}; + struct SyntaxLeaf* fNext{nullptr}; + }; + + std::vector<SyntaxLeaf> fLeafList; + SizeType fNumLeafs{0}; + + SizeType SizeOf() { return fNumLeafs; } + std::vector<SyntaxLeaf>& Get() { return fLeafList; } + SyntaxLeaf& At(SizeType index) { return fLeafList[index]; } +}; + +/// =========================================================== /// +/// find the perfect matching word in a haystack. +/// \param haystack base string +/// \param needle the string we search for. +/// \return if we found it or not. +/// =========================================================== /// +bool find_word(STLString haystack, STLString needle) noexcept; + +/// =========================================================== /// +/// find a word within strict conditions and returns a range of it. +/// \param haystack +/// \param needle +/// \return position of needle. +/// =========================================================== /// +SizeType find_word_range(STLString haystack, STLString needle) noexcept; + +/// =========================================================== /// +/// @brief Compiler backend, implements a frontend, such as C, C++... +/// See Toolchain, for some examples. +/// =========================================================== /// +class CompilerFrontendInterface { + public: + explicit CompilerFrontendInterface() = default; + virtual ~CompilerFrontendInterface() = default; + + NECTI_COPY_DEFAULT(CompilerFrontendInterface); + + /// =========================================================== /// + // NOTE: cast this to your user defined ast. + /// =========================================================== /// + typedef VoidPtr AstType; + + /// =========================================================== /// + //! @brief Compile a syntax tree ouf of the text. + //! Also takes the source file name for metadata. + /// =========================================================== /// + + virtual CompilerKit::SyntaxLeafList::SyntaxLeaf Compile(std::string text, std::string file) = 0; + + /// =========================================================== /// + //! @brief What language are we dealing with? + /// =========================================================== /// + virtual const char* Language(); + + /// =========================================================== /// + /// @brief Checks if language is a valid frontend. + /// =========================================================== /// + virtual bool IsValid(); +}; +} // namespace CompilerKit + +#include <CompilerKit/AST.inl>
\ No newline at end of file diff --git a/include/CompilerKit/AST.inl b/include/CompilerKit/AST.inl new file mode 100644 index 0000000..3dc9456 --- /dev/null +++ b/include/CompilerKit/AST.inl @@ -0,0 +1,63 @@ +/* ======================================== + + Copyright (C) 2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license + +======================================== */ + +namespace CompilerKit { +/// find the perfect matching word in a haystack. +/// \param haystack base string +/// \param needle the string we search for. +/// \return if we found it or not. +inline bool find_word(STLString haystack, STLString needle) noexcept { + auto index = haystack.find(needle); + + // check for needle validity. + if (index == STLString::npos) return false; + + // declare lambda + auto not_part_of_word = [&](int index) { + if (std::isspace(haystack[index]) || std::ispunct(haystack[index])) return true; + + if (index <= 0 || index >= haystack.size()) return true; + + return false; + }; + + return not_part_of_word(index - 1) && not_part_of_word(index + needle.size()); +} + +/// find a word within strict conditions and returns a range of it. +/// \param haystack +/// \param needle +/// \return position of needle. +inline SizeType find_word_range(STLString haystack, STLString needle) noexcept { + auto index = haystack.find(needle); + + // check for needle validity. + if (index == STLString::npos) return false; + + if (!isalnum((haystack[index + needle.size() + 1])) && + !isdigit(haystack[index + needle.size() + 1]) && + !isalnum((haystack[index - needle.size() - 1])) && + !isdigit(haystack[index - needle.size() - 1])) { + return index; + } + + return STLString::npos; +} + +/// =========================================================== /// +//! @brief What language are we dealing with? +/// =========================================================== /// +inline const char* CompilerFrontendInterface::Language() { + return kInvalidFrontend; +} + +/// =========================================================== /// +/// @brief Checks if language is a valid frontend. +/// =========================================================== /// +inline bool CompilerFrontendInterface::IsValid() { + return strcmp(this->Language(), kInvalidFrontend) > 0; +} +} // namespace CompilerKit
\ No newline at end of file diff --git a/include/CompilerKit/CodeGenerator.h b/include/CompilerKit/CodeGenerator.h new file mode 100644 index 0000000..383f170 --- /dev/null +++ b/include/CompilerKit/CodeGenerator.h @@ -0,0 +1,228 @@ +/* ======================================== + + Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license + +======================================== */ + +#pragma once + +#include <CompilerKit/Detail/Config.h> +#include <CompilerKit/Macros.h> +#include <cstring> + +#define CK_ASSEMBLY_INTERFACE : public ::CompilerKit::AssemblyInterface +#define CK_ENCODER : public ::CompilerKit::EncoderInterface + +namespace CompilerKit { +class AssemblyFactory; +class AssemblyInterface; + +/// =========================================================== /// +/// @brief Simple assembly factory +/// =========================================================== /// +class AssemblyFactory final { + public: + explicit AssemblyFactory() = default; + ~AssemblyFactory() = default; + + NECTI_COPY_DEFAULT(AssemblyFactory); + + public: + enum { + kArchInvalid = 0, + kArchAMD64 = 100, + kArch32x0, + kArch64x0, + kArchRISCV, + kArchPowerPC, + kArchAARCH64, + kArchUnknown, + kArchCount = kArchUnknown - kArchAMD64, + }; + + Int32 Compile(std::string sourceFile, const Int32& arch) noexcept; + + void Mount(AssemblyInterface* mountPtr) noexcept; + AssemblyInterface* Unmount() noexcept; + + private: + AssemblyInterface* fMounted{nullptr}; +}; + +/// =========================================================== /// +/// @brief Assembly to binary generator class. +/// @note This interface creates according to the CPU target of the child class. +/// =========================================================== /// +class AssemblyInterface { + public: + explicit AssemblyInterface() = default; + virtual ~AssemblyInterface() = default; + + NECTI_COPY_DEFAULT(AssemblyInterface); + + virtual UInt32 Arch() noexcept { return AssemblyFactory::kArchAMD64; } + + /// =========================================================== /// + /// @brief compile to object file. + /// @note Example C++ -> MASM -> AE object. + /// =========================================================== /// + virtual Int32 CompileToFormat(std::string src, Int32 arch) = 0; +}; + +/// =========================================================== /// +/// @brief Number casting unions for different sizes. +/// =========================================================== /// +union NumberCastBase { + NumberCastBase() = default; + ~NumberCastBase() = default; +}; + +union NumberCast64 final { + NumberCast64() = default; + explicit NumberCast64(UInt64 raw) : raw(raw) {} + + ~NumberCast64() { raw = 0; } + + static constexpr auto kLimit = 8; + + Char number[kLimit]; + UInt64 raw; +}; + +union NumberCast32 final { + NumberCast32() = default; + explicit NumberCast32(UInt32 raw) : raw(raw) {} + + ~NumberCast32() { raw = 0; } + + static constexpr auto kLimit = 4; + + Char number[kLimit]; + UInt32 raw; +}; + +union NumberCast16 final { + NumberCast16() = default; + explicit NumberCast16(UInt16 raw) : raw(raw) {} + + ~NumberCast16() { raw = 0; } + + static constexpr auto kLimit = 2; + + Char number[kLimit]; + UInt16 raw; +}; + +union NumberCast8 final { + NumberCast8() = default; + explicit NumberCast8(UInt8 raw) : raw(raw) {} + + ~NumberCast8() { raw = 0; } + + Char number; + UInt8 raw; +}; + +/// =========================================================== /// +/// @brief Assembly encoder interface. +/// =========================================================== /// +class EncoderInterface { + public: + explicit EncoderInterface() = default; + virtual ~EncoderInterface() = default; + + NECTI_COPY_DEFAULT(EncoderInterface); + + virtual std::string CheckLine(std::string line, std::string file) = 0; + virtual bool WriteLine(std::string line, std::string file) = 0; + virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) = 0; +}; + +/// =========================================================== /// +/// @brief Different architecture encoders. +/// =========================================================== /// + +#ifdef __ASM_NEED_AMD64__ + +class EncoderAMD64 final : public EncoderInterface { + public: + explicit EncoderAMD64() = default; + ~EncoderAMD64() override = default; + + NECTI_COPY_DEFAULT(EncoderAMD64); + + virtual std::string CheckLine(std::string line, std::string file) override; + virtual bool WriteLine(std::string line, std::string file) override; + virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) override; + + virtual bool WriteNumber16(const std::size_t& pos, std::string& from_what); + virtual bool WriteNumber32(const std::size_t& pos, std::string& from_what); + virtual bool WriteNumber8(const std::size_t& pos, std::string& from_what); +}; + +#endif // __ASM_NEED_AMD64__ + +#ifdef __ASM_NEED_ARM64__ + +class EncoderARM64 final : public EncoderInterface { + public: + explicit EncoderARM64() = default; + ~EncoderARM64() override = default; + + NECTI_COPY_DEFAULT(EncoderARM64); + + virtual std::string CheckLine(std::string line, std::string file) override; + virtual bool WriteLine(std::string line, std::string file) override; + virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) override; +}; + +#endif // __ASM_NEED_ARM64__ + +#ifdef __ASM_NEED_64x0__ + +class Encoder64x0 final : public EncoderInterface { + public: + explicit Encoder64x0() = default; + ~Encoder64x0() override = default; + + NECTI_COPY_DEFAULT(Encoder64x0); + + virtual std::string CheckLine(std::string line, std::string file) override; + virtual bool WriteLine(std::string line, std::string file) override; + virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) override; +}; + +#endif // __ASM_NEED_64x0__ + +#ifdef __ASM_NEED_32x0__ + +class Encoder32x0 final : public EncoderInterface { + public: + explicit Encoder32x0() = default; + ~Encoder32x0() override = default; + + NECTI_COPY_DEFAULT(Encoder32x0); + + virtual std::string CheckLine(std::string line, std::string file) override; + virtual bool WriteLine(std::string line, std::string file) override; + virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) override; +}; + +#endif // __ASM_NEED_32x0__ + +#ifdef __ASM_NEED_PPC__ + +class EncoderPowerPC final : public EncoderInterface { + public: + explicit EncoderPowerPC() = default; + ~EncoderPowerPC() override = default; + + NECTI_COPY_DEFAULT(EncoderPowerPC); + + virtual std::string CheckLine(std::string line, std::string file) override; + virtual bool WriteLine(std::string line, std::string file) override; + virtual bool WriteNumber(const std::size_t& pos, std::string& from_what) override; +}; + +#endif // __ASM_NEED_32x0__ +} // namespace CompilerKit diff --git a/include/CompilerKit/Detail/32x0.h b/include/CompilerKit/Detail/32x0.h new file mode 100644 index 0000000..fc3e0e9 --- /dev/null +++ b/include/CompilerKit/Detail/32x0.h @@ -0,0 +1,94 @@ +/* ======================================== + + Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license + +======================================== */ + +#pragma once + +#include <CompilerKit/Detail/Config.h> +#include <vector> + +// @brief Open32x0 support. +// @file Detail/32x0.h + +#define CK_ASM_OPCODE(__NAME, __OPCODE, __FUNCT3, __FUNCT7) \ + {.fName = __NAME, .fOpcode = __OPCODE, .fFunct3 = __FUNCT3, .fFunct7 = __FUNCT7}, + +#define kAsmImmediate 0x01 +#define kAsmSyscall 0x02 +#define kAsmJump 0x03 +#define kAsmNoArgs 0x04 + +#define kAsmByte 0 +#define kAsmHWord 1 +#define kAsmWord 2 + +struct CpuCode32x0 { + const char fName[32]; + uint8_t fOpcode; + uint8_t fSize; + uint8_t fFunct3; + uint8_t fFunct7; +}; + +#define kAsmDWordStr ".dword" /* 64 bit */ +#define kAsmWordStr ".word" /* 32-bit */ +#define kAsmHWordStr ".half" /* 16-bit */ +#define kAsmByteStr ".byte" /* 8-bit */ + +inline std::vector<CpuCode32x0> kOpcodes32x0 = { + CK_ASM_OPCODE("nop", 0b0100011, 0b000, kAsmNoArgs) // nothing to do. (1C) + CK_ASM_OPCODE("jmp", 0b1110011, 0b001, kAsmJump) // jump to branch (2C) + CK_ASM_OPCODE("mov", 0b0100011, 0b101, kAsmImmediate) // move registers (3C) + CK_ASM_OPCODE("psh", 0b0111011, 0b000, kAsmImmediate) // push to sp (2C) + CK_ASM_OPCODE("pop", 0b0111011, 0b001, kAsmImmediate) // pop from sp. (1C) + CK_ASM_OPCODE("lea", 0b0111011, 0b010, + kAsmImmediate) // setup stack and call, store address to CR (1C). + CK_ASM_OPCODE("ret", 0b0111011, 0b110, + kAsmImmediate) // return from procedure (2C). + CK_ASM_OPCODE("uc", 0b0111111, 0b000, kAsmSyscall) // user call (1C) + CK_ASM_OPCODE("kc", 0b0111111, 0b001, kAsmSyscall) // kernel call (1C) + CK_ASM_OPCODE("int", 0b0111111, 0b010, kAsmSyscall) // raise interrupt (1C) +}; + +// \brief 64x0 register prefix +// example: r32, r0 +// r32 -> sp +// r0 -> hw zero + +#define kAsmRegisterPrefix "r" +#define kAsmRegisterLimit 16 +#define kAsmPcRegister 17 +#define kAsmCrRegister 18 +#define kAsmSpRegister 5 + +/* return address register */ +#define kAsmRetRegister 19 + +///////////////////////////////////////////////////////////////////////////// + +// SYSTEM CALL ADDRESSING + +// | OPCODE | FUNCT3 | FUNCT7 | OFF | + +// IMMEDIATE ADDRESSING + +// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | +// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | REG | +// | OPCODE | FUNCT3 | FUNCT7 | REG | REG | OFF | + +// REG TO REG ADDRESSING + +// | OPCODE | FUNCT3 | FUNCT7 | REG | REG2 | + +//////////////////////////////// + +// LOAD/CALL INTERRUPTS + +// SET A HANDLER IN ADDRESS: TODO: find one +// DISABLE INTERRUPTS +// PROCESS INTERRUPT +// ENABLE INTERRUPTS + +//////////////////////////////// diff --git a/include/CompilerKit/Detail/64x0.h b/include/CompilerKit/Detail/64x0.h new file mode 100644 index 0000000..ba539f6 --- /dev/null +++ b/include/CompilerKit/Detail/64x0.h @@ -0,0 +1,100 @@ +/* ======================================== + + Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license + +======================================== */ + +#pragma once + +#include <CompilerKit/Detail/Config.h> +#include <vector> + +// @brief Open64x0 support. +// @file Detail/64x0.h + +#define CK_ASM_OPCODE(__NAME, __OPCODE, __FUNCT3, __FUNCT7) \ + {.fName = __NAME, .fOpcode = __OPCODE, .fFunct3 = __FUNCT3, .fFunct7 = __FUNCT7}, + +#define kAsmImmediate 0x01 +#define kAsmRegToReg 0x02 +#define kAsmSyscall 0x03 +#define kAsmJump 0x04 +#define kAsmNoArgs 0x00 + +typedef char e64k_character_t; +typedef uint8_t e64k_num_t; + +struct CpuOpcode64x0 { + const e64k_character_t fName[32]; + e64k_num_t fOpcode; + e64k_num_t fFunct3; + e64k_num_t fFunct7; +}; + +inline std::vector<CpuOpcode64x0> kOpcodes64x0 = { + CK_ASM_OPCODE("nop", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation. + CK_ASM_OPCODE("np", 0b0000000, 0b0000000, kAsmNoArgs) // no-operation. + CK_ASM_OPCODE("jlr", 0b1110011, 0b0000111, + kAsmJump) // jump to linked return register + CK_ASM_OPCODE("jrl", 0b1110011, 0b0001111, + kAsmJump) // jump from return register. + CK_ASM_OPCODE("mv", 0b0100011, 0b101, kAsmRegToReg) CK_ASM_OPCODE( + "bg", 0b1100111, 0b111, kAsmRegToReg) CK_ASM_OPCODE("bl", 0b1100111, 0b011, kAsmRegToReg) + CK_ASM_OPCODE("beq", 0b1100111, 0b000, kAsmRegToReg) + CK_ASM_OPCODE("bne", 0b1100111, 0b001, kAsmRegToReg) + CK_ASM_OPCODE("bge", 0b1100111, 0b101, kAsmRegToReg) + CK_ASM_OPCODE("ble", 0b1100111, 0b100, kAsmRegToReg) + CK_ASM_OPCODE("stw", 0b0001111, 0b100, kAsmImmediate) + CK_ASM_OPCODE("ldw", 0b0001111, 0b100, kAsmImmediate) + CK_ASM_OPCODE("lda", 0b0001111, 0b101, kAsmImmediate) + CK_ASM_OPCODE("sta", 0b0001111, 0b001, kAsmImmediate) + // add/sub without carry flag + CK_ASM_OPCODE("add", 0b0101011, 0b100, kAsmImmediate) + CK_ASM_OPCODE("sub", 0b0101011, 0b101, kAsmImmediate) + // add/sub with carry flag + CK_ASM_OPCODE("addc", 0b0101011, 0b110, kAsmImmediate) CK_ASM_OPCODE( + "subc", 0b0101011, 0b111, kAsmImmediate) CK_ASM_OPCODE("sc", 0b1110011, 0b00, kAsmSyscall)}; + +// \brief 64x0 register prefix +// example: r32, r0 +// r32 -> sp +// r0 -> hw zero + +#define kAsmFloatZeroRegister 0 +#define kAsmZeroRegister 0 + +#define kAsmRegisterPrefix "r" +#define kAsmRegisterLimit 30 +#define kAsmPcRegister 17 +#define kAsmCrRegister 18 +#define kAsmSpRegister 5 + +/* return address register */ +#define kAsmRetRegister 19 + +///////////////////////////////////////////////////////////////////////////// + +// SYSTEM CALL/JUMP ADDRESSING + +// | OPCODE | FUNCT3 | FUNCT7 | OFF | + +// IMMEDIATE ADDRESSING + +// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | +// | OPCODE | FUNCT3 | FUNCT7 | REG | OFF | REG | +// | OPCODE | FUNCT3 | FUNCT7 | REG | REG | OFF | + +// REG TO REG ADDRESSING + +// | OPCODE | FUNCT3 | FUNCT7 | REG | REG2 | + +//////////////////////////////// + +// LOAD/CALL INTERRUPTS + +// SET A HANDLER IN ADDRESS: +// DISABLE INTERRUPTS +// PROCESS INTERRUPT +// ENABLE INTERRUPTS + +//////////////////////////////// diff --git a/include/CompilerKit/Detail/AMD64.h b/include/CompilerKit/Detail/AMD64.h new file mode 100644 index 0000000..a123c02 --- /dev/null +++ b/include/CompilerKit/Detail/AMD64.h @@ -0,0 +1,50 @@ +/* ======================================== + + Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license + +======================================== */ + +#pragma once + +#include <CompilerKit/Detail/Config.h> +#include <vector> + +// @brief AMD64 support. +// @file Detail/AMD64.h + +#define CK_ASM_OPCODE(__NAME, __OPCODE) {.fName = __NAME, .fOpcode = __OPCODE}, + +typedef char i64_character_t; +typedef uint8_t i64_byte_t; +typedef uint16_t i64_hword_t; +typedef uint32_t i64_word_t; + +#define kAsmRegisterPrefix "r" + +struct CpuOpcodeAMD64 { + std::string fName; + i64_byte_t fPrefixBytes[4]; + i64_hword_t fOpcode; + i64_hword_t fModReg; + i64_word_t fDisplacment; + i64_word_t fImmediate; +}; + +/// these two are edge cases +#define kAsmIntOpcode 0xCC +#define kasmIntOpcodeAlt 0xCD + +#define kAsmJumpOpcode 0x0F80 +#define kJumpLimit 30 +#define kJumpLimitStandard 0xE3 +#define kJumpLimitStandardLimit 0xEB + +inline std::vector<CpuOpcodeAMD64> kOpcodesAMD64 = { + CK_ASM_OPCODE("int", 0xCD) CK_ASM_OPCODE("into", 0xCE) CK_ASM_OPCODE("intd", 0xF1) + CK_ASM_OPCODE("int3", 0xC3) CK_ASM_OPCODE("iret", 0xCF) CK_ASM_OPCODE("retf", 0xCB) + CK_ASM_OPCODE("retn", 0xC3) CK_ASM_OPCODE("ret", 0xC3) CK_ASM_OPCODE("sti", 0xfb) + CK_ASM_OPCODE("cli", 0xfa) CK_ASM_OPCODE("hlt", 0xf4) CK_ASM_OPCODE("nop", 0x90) + CK_ASM_OPCODE("mov", 0x48) CK_ASM_OPCODE("call", 0xFF) + CK_ASM_OPCODE("syscall", 0x0F) CK_ASM_OPCODE("xor", 0x48)}; + +#define kAsmRegisterLimit 16 diff --git a/include/CompilerKit/Detail/Aarch64.h b/include/CompilerKit/Detail/Aarch64.h new file mode 100644 index 0000000..1ce1719 --- /dev/null +++ b/include/CompilerKit/Detail/Aarch64.h @@ -0,0 +1,41 @@ +/* ======================================== + +Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license + +======================================== */ + +#pragma once + +#include <CompilerKit/Detail/Config.h> +#include <stdint.h> + +/// @brief ARM64 encoding support. +/// @file Detail/Aarch64.h + +struct CpuOpcodeArm64; + +/// @brief ARM64 opcode header. +struct PACKED CpuOpcodeArm64_Data final { + uint32_t fOpcode : 10; // Bits 31–22: Opcode for operation + uint32_t fRm : 5; // Bits 21–16: Source register Rm + uint32_t fShamt : 6; // Bits 15–10: Shift amount + uint32_t fRn : 5; // Bits 9–5: Source register Rn + uint32_t fRd : 5; // Bits 4–0: Destination register Rd +}; + +typedef struct { + uint32_t opcode : 6; // Bits 31–26: Branch opcode + int32_t offset : 26; // Bits 25–0: Signed offset (branch target) +} PACKED CpuOpcodeArm64_Branch; + +typedef struct { + uint32_t size : 2; // Bits 31–30: Size of the data + uint32_t opcode : 7; // Bits 29–23: Opcode for load/store + uint32_t offset : 12; // Bits 22–10: Offset + uint32_t rn : 5; // Bits 9–5: Base address register Rn + uint32_t rt : 5; // Bits 4–0: Target/source register Rt +} PACKED CpuOpcodeArm64_LoadStore; + +#define kAsmRegisterLimit (30) +#define kAsmRegisterPrefix "x" +#define kOpcodeARM64Count (1000) diff --git a/include/CompilerKit/Detail/Config.h b/include/CompilerKit/Detail/Config.h new file mode 100644 index 0000000..6137e2a --- /dev/null +++ b/include/CompilerKit/Detail/Config.h @@ -0,0 +1,64 @@ +/* ======================================== + + Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license + +======================================== */ + +#pragma once + +/// =========================================================== /// +/// @file detail/Config.h +/// @author Amlal El Mahrouss +/// @brief Basic defines and types for CompilerKit. +/// =========================================================== /// + +#include <CompilerKit/Detail/PreConfig.h> + +namespace CompilerKit { +inline constexpr int kBaseYear = 1900; +using STLString = std::string; + +inline STLString current_date() noexcept { + auto time_data = time(nullptr); + auto time_struct = gmtime(&time_data); + + STLString fmt = std::to_string(kBaseYear + time_struct->tm_year); + + fmt += "-"; + fmt += std::to_string(time_struct->tm_mon + 1); + fmt += "-"; + fmt += std::to_string(time_struct->tm_mday); + + return fmt; +} + +inline bool to_str(Char* str, Int32 limit, Int32 base) noexcept { + if (limit == 0) return false; + + Int32 copy_limit = limit; + Int32 cnt = 0; + Int32 ret = base; + + while (limit != 1) { + ret = ret % 10; + str[cnt] = ret; + + ++cnt; + --limit; + --ret; + } + + str[copy_limit] = '\0'; + return true; +} + +inline bool install_signal(Int32 signal, void (*handler)(int)) noexcept { + if (handler == nullptr) return false; + + if (::signal(signal, handler) == SIG_ERR) { + return false; + } + + return true; +} +} // namespace CompilerKit diff --git a/include/CompilerKit/Detail/Power64.h b/include/CompilerKit/Detail/Power64.h new file mode 100644 index 0000000..7c7f67c --- /dev/null +++ b/include/CompilerKit/Detail/Power64.h @@ -0,0 +1,1557 @@ +/* ======================================== + + Some modifications are copyrighted under: + Amlal El Mahrouss + + Original author: + Apple Inc + +======================================== */ + +#pragma once + +#include <stdint.h> + +/// @note Based of: +/// https://opensource.apple.com/source/cctools/cctools-750/as/ppc-opcode.h.auto.html + +#define kOpcodePPCCount (1073U) + +/* + * These defines are use in the cpus field of the instructions. If the field + * is zero it can execute on all cpus. The defines are or'ed together. This + * information is used to set the cpusubtype in the resulting object file. + */ +#define CPU601 0x1 +#define IMPL64 0x2 +#define OPTIONAL 0x4 +#define VMX 0x8 +#define CPU970 0x10 /* added to OPTIONAL insts that the 970 has */ +#define CPUMAHROUSS 0x12 /* optional mahrouss insts. */ + +enum OpcodeType { + NONE, /* no operand */ + JBSR, /* jbsr pseudo op */ + PCREL, /* PC relative (branch offset) */ + BADDR, /* Branch address (sign extended absolute address) */ + D, /* 16 bit displacement */ + DS, /* 14 bit displacement (double word) */ + SI, /* signed 16 bit immediate */ + UI, /* unsigned 16 bit immediate */ + HI, /* high 16 bit immediate (with truncation) */ + GREG, /* general register */ + G0REG, /* general register r1-r31 or 0 */ + FREG, /* float register */ + VREG, /* vector register */ + SGREG, /* segment register */ + SPREG, /* special register (or 10 bit number, 5 bit halves reversed) */ + BCND, /* branch condition opcode */ + CRF, /* condition register field */ + CRFONLY, /* condition register field only no expression allowed */ + sh, /* 6 bit number (0 - 63) (sh field, split and reversed) */ + mb, /* 6 bit number (0 - 63) (mb field, mb5 || mb0:4 reversed) */ + NUM, /* number */ + SNUM, /* signed number */ + NUM0, /* number (where 1<<width is the same as 0) */ + MBE, /* mask defined by MB and ME fields */ + FXM, /* 8-bit mask with only one bit set */ + ZERO /* the number zero */ +}; + +struct CpuOpcodePPC { + struct OpcodeType final { + uint32_t offset : 5; + uint32_t width : 5; + uint32_t type : 6; + }; + + uint32_t opcode; + const char* name; // c++ wants the string to be const, it makes sense here. + OpcodeType ops[5]; + uint32_t cpus; +}; + +inline CpuOpcodePPC kOpcodesPowerPC[] = { + {0x38000000, "addi", {{21, 5, GREG}, {16, 5, G0REG}, {0, 16, SI}}}, + {0x38000000, "li", {{21, 5, GREG}, {0, 16, SI}}}, + {0x3c000000, "addis", {{21, 5, GREG}, {16, 5, G0REG}, {0, 16, HI}}}, + {0x3c000000, "lis", {{21, 5, GREG}, {0, 16, HI}}}, + {0x30000000, "addic", {{21, 5, GREG}, {16, 5, GREG}, {0, 16, SI}}}, + {0x34000000, "addic.", {{21, 5, GREG}, {16, 5, GREG}, {0, 16, SI}}}, + {0x7c000214, "add", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000215, "add.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000614, "addo", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000615, "addo.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + + {0x7c000014, "addc", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000015, "addc.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000414, "addco", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000415, "addco.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + + {0x7c000114, "adde", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000115, "adde.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000514, "addeo", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000515, "addeo.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + + {0x7c0001d4, "addme", {{21, 5, GREG}, {16, 5, GREG}}}, + {0x7c0001d5, "addme.", {{21, 5, GREG}, {16, 5, GREG}}}, + {0x7c0005d4, "addmeo", {{21, 5, GREG}, {16, 5, GREG}}}, + {0x7c0005d5, "addmeo.", {{21, 5, GREG}, {16, 5, GREG}}}, + + {0x7c000194, "addze", {{21, 5, GREG}, {16, 5, GREG}}}, + {0x7c000195, "addze.", {{21, 5, GREG}, {16, 5, GREG}}}, + {0x7c000594, "addzeo", {{21, 5, GREG}, {16, 5, GREG}}}, + {0x7c000595, "addzeo.", {{21, 5, GREG}, {16, 5, GREG}}}, + + {0x70000000, "andi.", {{16, 5, GREG}, {21, 5, GREG}, {0, 16, UI}}}, + {0x74000000, "andis.", {{16, 5, GREG}, {21, 5, GREG}, {0, 16, UI}}}, + {0x7c000038, "and", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}}, + {0x7c000039, "and.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}}, + + {0x7c000078, "andc", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}}, + {0x7c000079, "andc.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}}, + + {0x48000000, "b", {{2, 24, PCREL}}}, + {0x48000002, "ba", {{2, 24, BADDR}}}, + {0x48000001, "bl", {{2, 24, PCREL}}}, + {0x48000003, "bla", {{2, 24, BADDR}}}, + + {0x48000001, "jbsr", {{0, 0, JBSR}, {2, 24, PCREL}}}, + {0x48000000, "jmp", {{0, 0, JBSR}, {2, 24, PCREL}}}, + + {0x40000000, "bc", {{21, 5, NUM}, {16, 5, NUM}, {2, 14, PCREL}}}, + {0x40000002, "bca", {{21, 5, NUM}, {16, 5, NUM}, {2, 14, BADDR}}}, + {0x40000001, "bcl", {{21, 5, NUM}, {16, 5, NUM}, {2, 14, PCREL}}}, + {0x40000003, "bcla", {{21, 5, NUM}, {16, 5, NUM}, {2, 14, BADDR}}}, + + {0x4c000420, "bcctr", {{21, 5, NUM}, {16, 5, NUM}}}, + {0x4c000420, "bcctr", {{21, 5, NUM}, {16, 5, NUM}, {11, 2, NUM}}}, + {0x4c000421, "bcctrl", {{21, 5, NUM}, {16, 5, NUM}}}, + {0x4c000421, "bcctrl", {{21, 5, NUM}, {16, 5, NUM}, {11, 2, NUM}}}, + {0x4c000020, "bclr", {{21, 5, NUM}, {16, 5, NUM}}}, + {0x4c000020, "bclr", {{21, 5, NUM}, {16, 5, NUM}, {11, 2, NUM}}}, + {0x4c000021, "bclrl", {{21, 5, NUM}, {16, 5, NUM}}}, + {0x4c000021, "bclrl", {{21, 5, NUM}, {16, 5, NUM}, {11, 2, NUM}}}, + + /* Basic branch mnemonics (assember extended mnemonics) */ + /* { 0x42800000, "b", {{2,14,PCREL}} }, overlaps */ + /* { 0x42800001, "bl", {{2,14,PCREL}} }, overlaps */ + {0x41800000, "bt", {{16, 5, BCND}, {2, 14, PCREL}}}, + {0x41800001, "btl", {{16, 5, BCND}, {2, 14, PCREL}}}, + {0x40800000, "bf", {{16, 5, BCND}, {2, 14, PCREL}}}, + {0x40800001, "bfl", {{16, 5, BCND}, {2, 14, PCREL}}}, + {0x42000000, "bdnz", {{2, 14, PCREL}}}, + {0x42000001, "bdnzl", {{2, 14, PCREL}}}, + {0x41000000, "bdnzt", {{16, 5, BCND}, {2, 14, PCREL}}}, + {0x41000001, "bdnztl", {{16, 5, BCND}, {2, 14, PCREL}}}, + {0x40000000, "bdnzf", {{16, 5, BCND}, {2, 14, PCREL}}}, + {0x40000001, "bdnzfl", {{16, 5, BCND}, {2, 14, PCREL}}}, + {0x42400000, "bdz", {{2, 14, PCREL}}}, + {0x42400001, "bdzl", {{2, 14, PCREL}}}, + {0x41400000, "bdzt", {{16, 5, BCND}, {2, 14, PCREL}}}, + {0x41400001, "bdztl", {{16, 5, BCND}, {2, 14, PCREL}}}, + {0x40400000, "bdzf", {{16, 5, BCND}, {2, 14, PCREL}}}, + {0x40400001, "bdzfl", {{16, 5, BCND}, {2, 14, PCREL}}}, + + /* { 0x42800002, "ba", {{2,14,BADDR}} }, overlaps */ + /* { 0x42800003, "bla", {{2,14,BADDR}} }, overlaps */ + {0x41800002, "bta", {{16, 5, BCND}, {2, 14, BADDR}}}, + {0x41800003, "btla", {{16, 5, BCND}, {2, 14, BADDR}}}, + {0x40800002, "bfa", {{16, 5, BCND}, {2, 14, BADDR}}}, + {0x40800003, "bfla", {{16, 5, BCND}, {2, 14, BADDR}}}, + {0x42000002, "bdnza", {{2, 14, BADDR}}}, + {0x42000003, "bdnzla", {{2, 14, BADDR}}}, + {0x41000002, "bdnzta", {{16, 5, BCND}, {2, 14, BADDR}}}, + {0x41000003, "bdnztla", {{16, 5, BCND}, {2, 14, BADDR}}}, + {0x40000002, "bdnzfa", {{16, 5, BCND}, {2, 14, BADDR}}}, + {0x40000003, "bdnzfla", {{16, 5, BCND}, {2, 14, BADDR}}}, + {0x42400002, "bdza", {{2, 14, BADDR}}}, + {0x42400003, "bdzla", {{2, 14, BADDR}}}, + {0x41400002, "bdzta", {{16, 5, BCND}, {2, 14, BADDR}}}, + {0x41400003, "bdztla", {{16, 5, BCND}, {2, 14, BADDR}}}, + {0x40400002, "bdzfa", {{16, 5, BCND}, {2, 14, BADDR}}}, + {0x40400003, "bdzfla", {{16, 5, BCND}, {2, 14, BADDR}}}, + + { + 0x4e800020, + "blr", + }, + {0x4e800020, "blr", {{11, 2, NUM}}}, + { + 0x4e800021, + "blrl", + }, + {0x4e800021, "blrl", {{11, 2, NUM}}}, + {0x4d800020, "btlr", {{16, 5, BCND}}}, + {0x4d800020, "btlr", {{16, 5, BCND}, {11, 2, NUM}}}, + {0x4d800021, "btlrl", {{16, 5, BCND}}}, + {0x4d800021, "btlrl", {{16, 5, BCND}, {11, 2, NUM}}}, + {0x4c800020, "bflr", {{16, 5, BCND}}}, + {0x4c800020, "bflr", {{16, 5, BCND}, {11, 2, NUM}}}, + {0x4c800021, "bflrl", {{16, 5, BCND}}}, + {0x4c800021, "bflrl", {{16, 5, BCND}, {11, 2, NUM}}}, + { + 0x4e000020, + "bdnzlr", + }, + {0x4e000020, "bdnzlr", {{11, 2, NUM}}}, + { + 0x4e000021, + "bdnzlrl", + }, + {0x4e000021, "bdnzlrl", {{11, 2, NUM}}}, + {0x4d000020, "bdnztlr", {{16, 5, BCND}}}, + {0x4d000020, "bdnztlr", {{16, 5, BCND}, {11, 2, NUM}}}, + {0x4d000021, "bdnztlrl", {{16, 5, BCND}}}, + {0x4d000021, "bdnztlrl", {{16, 5, BCND}, {11, 2, NUM}}}, + {0x4c000020, "bdnzflr", {{16, 5, BCND}}}, + {0x4c000020, "bdnzflr", {{16, 5, BCND}, {11, 2, NUM}}}, + {0x4c000021, "bdnzflrl", {{16, 5, BCND}}}, + {0x4c000021, "bdnzflrl", {{16, 5, BCND}, {11, 2, NUM}}}, + { + 0x4e400020, + "bdzlr", + }, + {0x4e400020, "bdzlr", {{11, 2, NUM}}}, + { + 0x4e400021, + "bdzlrl", + }, + {0x4e400021, "bdzlrl", {{11, 2, NUM}}}, + {0x4d400020, "bdztlr", {{16, 5, BCND}}}, + {0x4d400020, "bdztlr", {{16, 5, BCND}, {11, 2, NUM}}}, + {0x4d400021, "bdztlrl", {{16, 5, BCND}}}, + {0x4d400021, "bdztlrl", {{16, 5, BCND}, {11, 2, NUM}}}, + {0x4c400020, "bdzflr", {{16, 5, BCND}}}, + {0x4c400020, "bdzflr", {{16, 5, BCND}, {11, 2, NUM}}}, + {0x4c400021, "bdzflrl", {{16, 5, BCND}}}, + {0x4c400021, "bdzflrl", {{16, 5, BCND}, {11, 2, NUM}}}, + + {0x4c000420, "bctr", {{21, 5, NUM}, {16, 5, NUM}}}, + { + 0x4e800420, + "bctr", + }, + {0x4e800420, "bctr", {{11, 2, NUM}}}, + {0x4c000421, "bctrl", {{21, 5, NUM}, {16, 5, NUM}}}, + { + 0x4e800421, + "bctrl", + }, + {0x4e800421, "bctrl", {{11, 2, NUM}}}, + {0x4d800420, "btctr", {{16, 5, BCND}}}, + {0x4d800420, "btctr", {{16, 5, BCND}, {11, 2, NUM}}}, + {0x4d800421, "btctrl", {{16, 5, BCND}}}, + {0x4d800421, "btctrl", {{16, 5, BCND}, {11, 2, NUM}}}, + {0x4c800420, "bfctr", {{16, 5, BCND}}}, + {0x4c800420, "bfctr", {{16, 5, BCND}, {11, 2, NUM}}}, + {0x4c800421, "bfctrl", {{16, 5, BCND}}}, + {0x4c800421, "bfctrl", {{16, 5, BCND}, {11, 2, NUM}}}, + + /* branch mnemonics incorporating conditions (assember extended mnemonics) + */ + {0x41800000, "blt", {{16, 5, CRF}, {2, 14, PCREL}}}, + {0x41800000, "blt", {{2, 14, PCREL}}}, + {0x41800001, "bltl", {{16, 5, CRF}, {2, 14, PCREL}}}, + {0x41800001, "bltl", {{2, 14, PCREL}}}, + {0x40810000, "ble", {{16, 5, CRF}, {2, 14, PCREL}}}, + {0x40810000, "ble", {{2, 14, PCREL}}}, + {0x40810001, "blel", {{16, 5, CRF}, {2, 14, PCREL}}}, + {0x40810001, "blel", {{2, 14, PCREL}}}, + {0x41820000, "beq", {{16, 5, CRF}, {2, 14, PCREL}}}, + {0x41820000, "beq", {{2, 14, PCREL}}}, + {0x41820001, "beql", {{16, 5, CRF}, {2, 14, PCREL}}}, + {0x41820001, "beql", {{2, 14, PCREL}}}, + {0x40800000, "bge", {{16, 5, CRF}, {2, 14, PCREL}}}, + {0x40800000, "bge", {{2, 14, PCREL}}}, + {0x40800001, "bgel", {{16, 5, CRF}, {2, 14, PCREL}}}, + {0x40800001, "bgel", {{2, 14, PCREL}}}, + {0x41810000, "bgt", {{16, 5, CRF}, {2, 14, PCREL}}}, + {0x41810000, "bgt", {{2, 14, PCREL}}}, + {0x41810001, "bgtl", {{16, 5, CRF}, {2, 14, PCREL}}}, + {0x41810001, "bgtl", {{2, 14, PCREL}}}, + {0x40800000, "bnl", {{16, 5, CRF}, {2, 14, PCREL}}}, + {0x40800000, "bnl", {{2, 14, PCREL}}}, + {0x40800001, "bnll", {{16, 5, CRF}, {2, 14, PCREL}}}, + {0x40800001, "bnll", {{2, 14, PCREL}}}, + {0x40820000, "bne", {{16, 5, CRF}, {2, 14, PCREL}}}, + {0x40820000, "bne", {{2, 14, PCREL}}}, + {0x40820001, "bnel", {{16, 5, CRF}, {2, 14, PCREL}}}, + {0x40820001, "bnel", {{2, 14, PCREL}}}, + {0x40810000, "bng", {{16, 5, CRF}, {2, 14, PCREL}}}, + {0x40810000, "bng", {{2, 14, PCREL}}}, + {0x40810001, "bngl", {{16, 5, CRF}, {2, 14, PCREL}}}, + {0x40810001, "bngl", {{2, 14, PCREL}}}, + {0x41830000, "bso", {{16, 5, CRF}, {2, 14, PCREL}}}, + {0x41830000, "bso", {{2, 14, PCREL}}}, + {0x41830001, "bsol", {{16, 5, CRF}, {2, 14, PCREL}}}, + {0x41830001, "bsol", {{2, 14, PCREL}}}, + {0x40830000, "bns", {{16, 5, CRF}, {2, 14, PCREL}}}, + {0x40830000, "bns", {{2, 14, PCREL}}}, + {0x40830001, "bnsl", {{16, 5, CRF}, {2, 14, PCREL}}}, + {0x40830001, "bnsl", {{2, 14, PCREL}}}, + {0x41830000, "bun", {{16, 5, CRF}, {2, 14, PCREL}}}, + {0x41830000, "bun", {{2, 14, PCREL}}}, + {0x41830001, "bunl", {{16, 5, CRF}, {2, 14, PCREL}}}, + {0x41830001, "bunl", {{2, 14, PCREL}}}, + {0x40830000, "bnu", {{16, 5, CRF}, {2, 14, PCREL}}}, + {0x40830000, "bnu", {{2, 14, PCREL}}}, + {0x40830001, "bnul", {{16, 5, CRF}, {2, 14, PCREL}}}, + {0x40830001, "bnul", {{2, 14, PCREL}}}, + + {0x41800002, "blta", {{16, 5, CRF}, {2, 14, BADDR}}}, + {0x41800002, "blta", {{2, 14, BADDR}}}, + {0x41800003, "bltla", {{16, 5, CRF}, {2, 14, BADDR}}}, + {0x41800003, "bltla", {{2, 14, BADDR}}}, + {0x40810002, "blea", {{16, 5, CRF}, {2, 14, BADDR}}}, + {0x40810002, "blea", {{2, 14, BADDR}}}, + {0x40810003, "blela", {{16, 5, CRF}, {2, 14, BADDR}}}, + {0x40810003, "blela", {{2, 14, BADDR}}}, + {0x41820002, "beqa", {{16, 5, CRF}, {2, 14, BADDR}}}, + {0x41820002, "beqa", {{2, 14, BADDR}}}, + {0x41820003, "beqla", {{16, 5, CRF}, {2, 14, BADDR}}}, + {0x41820003, "beqla", {{2, 14, BADDR}}}, + {0x40800002, "bgea", {{16, 5, CRF}, {2, 14, BADDR}}}, + {0x40800002, "bgea", {{2, 14, BADDR}}}, + {0x40800003, "bgela", {{16, 5, CRF}, {2, 14, BADDR}}}, + {0x40800003, "bgela", {{2, 14, BADDR}}}, + {0x41810002, "bgta", {{16, 5, CRF}, {2, 14, BADDR}}}, + {0x41810002, "bgta", {{2, 14, BADDR}}}, + {0x41810003, "bgtla", {{16, 5, CRF}, {2, 14, BADDR}}}, + {0x41810003, "bgtla", {{2, 14, BADDR}}}, + {0x40800002, "bnla", {{16, 5, CRF}, {2, 14, BADDR}}}, + {0x40800002, "bnla", {{2, 14, BADDR}}}, + {0x40800003, "bnlla", {{16, 5, CRF}, {2, 14, BADDR}}}, + {0x40800003, "bnlla", {{2, 14, BADDR}}}, + {0x40820002, "bnea", {{16, 5, CRF}, {2, 14, BADDR}}}, + {0x40820002, "bnea", {{2, 14, BADDR}}}, + {0x40820003, "bnela", {{16, 5, CRF}, {2, 14, BADDR}}}, + {0x40820003, "bnela", {{2, 14, BADDR}}}, + {0x40810002, "bnga", {{16, 5, CRF}, {2, 14, BADDR}}}, + {0x40810002, "bnga", {{2, 14, BADDR}}}, + {0x40810003, "bngla", {{16, 5, CRF}, {2, 14, BADDR}}}, + {0x40810003, "bngla", {{2, 14, BADDR}}}, + {0x41830002, "bsoa", {{16, 5, CRF}, {2, 14, BADDR}}}, + {0x41830002, "bsoa", {{2, 14, BADDR}}}, + {0x41830003, "bsola", {{16, 5, CRF}, {2, 14, BADDR}}}, + {0x41830003, "bsola", {{2, 14, BADDR}}}, + {0x40830002, "bnsa", {{16, 5, CRF}, {2, 14, BADDR}}}, + {0x40830002, "bnsa", {{2, 14, BADDR}}}, + {0x40830003, "bnsla", {{16, 5, CRF}, {2, 14, BADDR}}}, + {0x40830003, "bnsla", {{2, 14, BADDR}}}, + {0x41830002, "buna", {{16, 5, CRF}, {2, 14, BADDR}}}, + {0x41830002, "buna", {{2, 14, BADDR}}}, + {0x41830003, "bunla", {{16, 5, CRF}, {2, 14, BADDR}}}, + {0x41830003, "bunla", {{2, 14, BADDR}}}, + {0x40830002, "bnua", {{16, 5, CRF}, {2, 14, BADDR}}}, + {0x40830002, "bnua", {{2, 14, BADDR}}}, + {0x40830003, "bnula", {{16, 5, CRF}, {2, 14, BADDR}}}, + {0x40830003, "bnula", {{2, 14, BADDR}}}, + + {0x4d800020, "bltlr", {{16, 5, CRF}}}, + {0x4d800020, "bltlr", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4d800020, + "bltlr", + }, + {0x4d800021, "bltlrl", {{16, 5, CRF}}}, + {0x4d800021, "bltlrl", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4d800021, + "bltlrl", + }, + {0x4c810020, "blelr", {{16, 5, CRF}}}, + {0x4c810020, "blelr", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4c810020, + "blelr", + }, + {0x4c810021, "blelrl", {{16, 5, CRF}}}, + {0x4c810021, "blelrl", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4c810021, + "blelrl", + }, + {0x4d820020, "beqlr", {{16, 5, CRF}}}, + {0x4d820020, "beqlr", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4d820020, + "beqlr", + }, + {0x4d820021, "beqlrl", {{16, 5, CRF}}}, + {0x4d820021, "beqlrl", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4d820021, + "beqlrl", + }, + {0x4c800020, "bgelr", {{16, 5, CRF}}}, + {0x4c800020, "bgelr", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4c800020, + "bgelr", + }, + {0x4c800021, "bgelrl", {{16, 5, CRF}}}, + {0x4c800021, "bgelrl", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4c800021, + "bgelrl", + }, + {0x4d810020, "bgtlr", {{16, 5, CRF}}}, + {0x4d810020, "bgtlr", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4d810020, + "bgtlr", + }, + {0x4d810021, "bgtlrl", {{16, 5, CRF}}}, + {0x4d810021, "bgtlrl", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4d810021, + "bgtlrl", + }, + {0x4c800020, "bnllr", {{16, 5, CRF}}}, + {0x4c800020, "bnllr", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4c800020, + "bnllr", + }, + {0x4c800021, "bnllrl", {{16, 5, CRF}}}, + {0x4c800021, "bnllrl", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4c800021, + "bnllrl", + }, + {0x4c820020, "bnelr", {{16, 5, CRF}}}, + {0x4c820020, "bnelr", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4c820020, + "bnelr", + }, + {0x4c820021, "bnelrl", {{16, 5, CRF}}}, + {0x4c820021, "bnelrl", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4c820021, + "bnelrl", + }, + {0x4c810020, "bnglr", {{16, 5, CRF}}}, + {0x4c810020, "bnglr", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4c810020, + "bnglr", + }, + {0x4c810021, "bnglrl", {{16, 5, CRF}}}, + {0x4c810021, "bnglrl", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4c810021, + "bnglrl", + }, + {0x4d830020, "bsolr", {{16, 5, CRF}}}, + {0x4d830020, "bsolr", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4d830020, + "bsolr", + }, + {0x4d830021, "bsolrl", {{16, 5, CRF}}}, + {0x4d830021, "bsolrl", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4d830021, + "bsolrl", + }, + {0x4c830020, "bnslr", {{16, 5, CRF}}}, + {0x4c830020, "bnslr", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4c830020, + "bnslr", + }, + {0x4c830021, "bnslrl", {{16, 5, CRF}}}, + {0x4c830021, "bnslrl", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4c830021, + "bnslrl", + }, + {0x4d830020, "bunlr", {{16, 5, CRF}}}, + {0x4d830020, "bunlr", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4d830020, + "bunlr", + }, + {0x4d830021, "bunlrl", {{16, 5, CRF}}}, + {0x4d830021, "bunlrl", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4d830021, + "bunlrl", + }, + {0x4c830020, "bnulr", {{16, 5, CRF}}}, + {0x4c830020, "bnulr", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4c830020, + "bnulr", + }, + {0x4c830021, "bnulrl", {{16, 5, CRF}}}, + {0x4c830021, "bnulrl", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4c830021, + "bnulrl", + }, + + {0x4d800420, "bltctr", {{16, 5, CRF}}}, + {0x4d800420, "bltctr", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4d800420, + "bltctr", + }, + {0x4d800421, "bltctrl", {{16, 5, CRF}}}, + {0x4d800421, "bltctrl", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4d800421, + "bltctrl", + }, + {0x4c810420, "blectr", {{16, 5, CRF}}}, + {0x4c810420, "blectr", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4c810420, + "blectr", + }, + {0x4c810421, "blectrl", {{16, 5, CRF}}}, + {0x4c810421, "blectrl", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4c810421, + "blectrl", + }, + {0x4d820420, "beqctr", {{16, 5, CRF}}}, + {0x4d820420, "beqctr", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4d820420, + "beqctr", + }, + {0x4d820421, "beqctrl", {{16, 5, CRF}}}, + {0x4d820421, "beqctrl", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4d820421, + "beqctrl", + }, + {0x4c800420, "bgectr", {{16, 5, CRF}}}, + {0x4c800420, "bgectr", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4c800420, + "bgectr", + }, + {0x4c800421, "bgectrl", {{16, 5, CRF}}}, + {0x4c800421, "bgectrl", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4c800421, + "bgectrl", + }, + {0x4d810420, "bgtctr", {{16, 5, CRF}}}, + {0x4d810420, "bgtctr", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4d810420, + "bgtctr", + }, + {0x4d810421, "bgtctrl", {{16, 5, CRF}}}, + {0x4d810421, "bgtctrl", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4d810421, + "bgtctrl", + }, + {0x4c800420, "bnlctr", {{16, 5, CRF}}}, + {0x4c800420, "bnlctr", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4c800420, + "bnlctr", + }, + {0x4c800421, "bnlctrl", {{16, 5, CRF}}}, + {0x4c800421, "bnlctrl", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4c800421, + "bnlctrl", + }, + {0x4c820420, "bnectr", {{16, 5, CRF}}}, + {0x4c820420, "bnectr", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4c820420, + "bnectr", + }, + {0x4c820421, "bnectrl", {{16, 5, CRF}}}, + {0x4c820421, "bnectrl", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4c820421, + "bnectrl", + }, + {0x4c810420, "bngctr", {{16, 5, CRF}}}, + {0x4c810420, "bngctr", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4c810420, + "bngctr", + }, + {0x4c810421, "bngctrl", {{16, 5, CRF}}}, + {0x4c810421, "bngctrl", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4c810421, + "bngctrl", + }, + {0x4d830420, "bsoctr", {{16, 5, CRF}}}, + {0x4d830420, "bsoctr", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4d830420, + "bsoctr", + }, + {0x4d830421, "bsoctrl", {{16, 5, CRF}}}, + {0x4d830421, "bsoctrl", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4d830421, + "bsoctrl", + }, + {0x4c830420, "bnsctr", {{16, 5, CRF}}}, + {0x4c830420, "bnsctr", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4c830420, + "bnsctr", + }, + {0x4c830421, "bnsctrl", {{16, 5, CRF}}}, + {0x4c830421, "bnsctrl", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4c830421, + "bnsctrl", + }, + {0x4d830420, "bunctr", {{16, 5, CRF}}}, + {0x4d830420, "bunctr", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4d830420, + "bunctr", + }, + {0x4d830421, "bunctrl", {{16, 5, CRF}}}, + {0x4d830421, "bunctrl", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4d830421, + "bunctrl", + }, + {0x4c830420, "bnuctr", {{16, 5, CRF}}}, + {0x4c830420, "bnuctr", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4c830420, + "bnuctr", + }, + {0x4c830421, "bnuctrl", {{16, 5, CRF}}}, + {0x4c830421, "bnuctrl", {{16, 5, CRF}, {11, 2, NUM}}}, + { + 0x4c830421, + "bnuctrl", + }, + + {0x2c000000, "cmpi", {{21, 5, CRFONLY}, {16, 5, GREG}, {0, 16, SI}}}, + {0x2c000000, "cmpi", {{21, 5, CRFONLY}, {21, 1, NUM}, {16, 5, GREG}, {0, 16, SI}}}, + {0x2c000000, "cmpi", {{23, 3, NUM}, {16, 5, GREG}, {0, 16, SI}}}, + {0x2c000000, "cmpi", {{23, 3, NUM}, {21, 1, NUM}, {16, 5, GREG}, {0, 16, SI}}}, + {0x2c000000, "cmpwi", {{16, 5, GREG}, {0, 16, SI}}}, + {0x2c000000, "cmpwi", {{21, 5, CRFONLY}, {16, 5, GREG}, {0, 16, SI}}}, + {0x2c000000, "cmpwi", {{23, 3, NUM}, {16, 5, GREG}, {0, 16, SI}}}, + {0x2c200000, "cmpdi", {{16, 5, GREG}, {0, 16, SI}}}, + {0x2c200000, "cmpdi", {{21, 5, CRFONLY}, {16, 5, GREG}, {0, 16, SI}}}, + {0x2c200000, "cmpdi", {{23, 3, NUM}, {16, 5, GREG}, {0, 16, SI}}}, + + {0x7c000000, "cmp", {{21, 5, CRFONLY}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000000, "cmp", {{21, 5, CRFONLY}, {21, 1, NUM}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000000, "cmp", {{23, 3, NUM}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000000, "cmp", {{23, 3, NUM}, {21, 1, NUM}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000000, "cmpw", {{16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000000, "cmpw", {{21, 5, CRFONLY}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000000, "cmpw", {{23, 3, NUM}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c200000, "cmpd", {{16, 5, GREG}, {11, 5, GREG}}}, + {0x7c200000, "cmpd", {{21, 5, CRFONLY}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c200000, "cmpd", {{23, 3, NUM}, {16, 5, GREG}, {11, 5, GREG}}}, + + {0x28000000, "cmpli", {{21, 5, CRFONLY}, {16, 5, GREG}, {0, 16, UI}}}, + {0x28000000, "cmpli", {{21, 5, CRFONLY}, {21, 1, NUM}, {16, 5, GREG}, {0, 16, UI}}}, + {0x28000000, "cmpli", {{23, 3, NUM}, {16, 5, GREG}, {0, 16, UI}}}, + {0x28000000, "cmpli", {{23, 3, NUM}, {21, 1, NUM}, {16, 5, GREG}, {0, 16, UI}}}, + {0x28000000, "cmplwi", {{16, 5, GREG}, {0, 16, UI}}}, + {0x28000000, "cmplwi", {{21, 5, CRFONLY}, {16, 5, GREG}, {0, 16, UI}}}, + {0x28000000, "cmplwi", {{23, 3, NUM}, {16, 5, GREG}, {0, 16, UI}}}, + {0x28200000, "cmpldi", {{16, 5, GREG}, {0, 16, UI}}}, + {0x28200000, "cmpldi", {{21, 5, CRFONLY}, {16, 5, GREG}, {0, 16, UI}}}, + {0x28200000, "cmpldi", {{23, 3, NUM}, {16, 5, GREG}, {0, 16, UI}}}, + + {0x7c000040, "cmpl", {{21, 5, CRFONLY}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000040, "cmpl", {{21, 5, CRFONLY}, {21, 1, NUM}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000040, "cmpl", {{23, 3, NUM}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000040, "cmpl", {{23, 3, NUM}, {21, 1, NUM}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000040, "cmplw", {{16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000040, "cmplw", {{21, 5, CRFONLY}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000040, "cmplw", {{23, 3, NUM}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c200040, "cmpld", {{16, 5, GREG}, {11, 5, GREG}}}, + {0x7c200040, "cmpld", {{21, 5, CRFONLY}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c200040, "cmpld", {{23, 3, NUM}, {16, 5, GREG}, {11, 5, GREG}}}, + + {0x7c000034, "cntlzw", {{16, 5, GREG}, {21, 5, GREG}}}, + {0x7c000035, "cntlzw.", {{16, 5, GREG}, {21, 5, GREG}}}, + {0x7c000074, "cntlzd", {{16, 5, GREG}, {21, 5, GREG}}, IMPL64}, + {0x7c000075, "cntlzd.", {{16, 5, GREG}, {21, 5, GREG}}, IMPL64}, + + {0x4c000202, "crand", {{21, 5, NUM}, {16, 5, NUM}, {11, 5, NUM}}}, + {0x4c000102, "crandc", {{21, 5, NUM}, {16, 5, NUM}, {11, 5, NUM}}}, + {0x4c000242, "creqv", {{21, 5, NUM}, {16, 5, NUM}, {11, 5, NUM}}}, + {0x4c0001c2, "crnand", {{21, 5, NUM}, {16, 5, NUM}, {11, 5, NUM}}}, + {0x4c000042, "crnor", {{21, 5, NUM}, {16, 5, NUM}, {11, 5, NUM}}}, + {0x4c000382, "cror", {{21, 5, NUM}, {16, 5, NUM}, {11, 5, NUM}}}, + {0x4c000342, "crorc", {{21, 5, NUM}, {16, 5, NUM}, {11, 5, NUM}}}, + {0x4c000182, "crxor", {{21, 5, NUM}, {16, 5, NUM}, {11, 5, NUM}}}, + + {0x7c0003d2, "divd", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + {0x7c0003d3, "divd.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + {0x7c0007d2, "divdo", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + {0x7c0007d3, "divdo.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + + {0x7c000392, "divdu", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + {0x7c000393, "divdu.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + {0x7c000792, "divduo", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + {0x7c000793, "divduo.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + + {0x7c0003d6, "divw", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c0003d7, "divw.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c0007d6, "divwo", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c0007d7, "divwo.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + + {0x7c000396, "divwu", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000397, "divwu.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000796, "divwuo", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000797, "divwuo.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + + {0x7c000238, "eqv", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}}, + {0x7c000239, "eqv.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}}, + + {0x7c000774, "extsb", {{16, 5, GREG}, {21, 5, GREG}}}, + {0x7c000775, "extsb.", {{16, 5, GREG}, {21, 5, GREG}}}, + {0x7c000734, "extsh", {{16, 5, GREG}, {21, 5, GREG}}}, + {0x7c000735, "extsh.", {{16, 5, GREG}, {21, 5, GREG}}}, + {0x7c0007b4, "extsw", {{16, 5, GREG}, {21, 5, GREG}}, IMPL64}, + {0x7c0007b5, "extsw.", {{16, 5, GREG}, {21, 5, GREG}}, IMPL64}, + + {0xfc00002a, "fadd", {{21, 5, FREG}, {16, 5, FREG}, {11, 5, FREG}}}, + {0xfc00002b, "fadd.", {{21, 5, FREG}, {16, 5, FREG}, {11, 5, FREG}}}, + {0xec00002a, "fadds", {{21, 5, FREG}, {16, 5, FREG}, {11, 5, FREG}}}, + {0xec00002b, "fadds.", {{21, 5, FREG}, {16, 5, FREG}, {11, 5, FREG}}}, + {0xfc000028, "fsub", {{21, 5, FREG}, {16, 5, FREG}, {11, 5, FREG}}}, + {0xfc000029, "fsub.", {{21, 5, FREG}, {16, 5, FREG}, {11, 5, FREG}}}, + {0xec000028, "fsubs", {{21, 5, FREG}, {16, 5, FREG}, {11, 5, FREG}}}, + {0xec000029, "fsubs.", {{21, 5, FREG}, {16, 5, FREG}, {11, 5, FREG}}}, + {0xfc000032, "fmul", {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}}}, + {0xfc000033, "fmul.", {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}}}, + {0xec000032, "fmuls", {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}}}, + {0xec000033, "fmuls.", {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}}}, + {0xfc000024, "fdiv", {{21, 5, FREG}, {16, 5, FREG}, {11, 5, FREG}}}, + {0xfc000025, "fdiv.", {{21, 5, FREG}, {16, 5, FREG}, {11, 5, FREG}}}, + {0xec000024, "fdivs", {{21, 5, FREG}, {16, 5, FREG}, {11, 5, FREG}}}, + {0xec000025, "fdivs.", {{21, 5, FREG}, {16, 5, FREG}, {11, 5, FREG}}}, + + {0xfc00003a, "fmadd", {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}}, + {0xfc00003b, "fmadd.", {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}}, + {0xec00003a, "fmadds", {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}}, + {0xec00003b, "fmadds.", {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}}, + {0xfc000038, "fmsub", {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}}, + {0xfc000039, "fmsub.", {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}}, + {0xec000038, "fmsubs", {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}}, + {0xec000039, "fmsubs.", {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}}, + {0xfc00003e, "fnmadd", {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}}, + {0xfc00003f, "fnmadd.", {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}}, + {0xec00003e, "fnmadds", {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}}, + {0xec00003f, "fnmadds.", {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}}, + {0xfc00003c, "fnmsub", {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}}, + {0xfc00003d, "fnmsub.", {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}}, + {0xec00003c, "fnmsubs", {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}}, + {0xec00003d, "fnmsubs.", {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}}, + + {0xfc000090, "fmr", {{21, 5, FREG}, {11, 5, FREG}}}, + {0xfc000091, "fmr.", {{21, 5, FREG}, {11, 5, FREG}}}, + {0xfc000210, "fabs", {{21, 5, FREG}, {11, 5, FREG}}}, + {0xfc000211, "fabs.", {{21, 5, FREG}, {11, 5, FREG}}}, + {0xfc000050, "fneg", {{21, 5, FREG}, {11, 5, FREG}}}, + {0xfc000051, "fneg.", {{21, 5, FREG}, {11, 5, FREG}}}, + {0xfc000110, "fnabs", {{21, 5, FREG}, {11, 5, FREG}}}, + {0xfc000111, "fnabs.", {{21, 5, FREG}, {11, 5, FREG}}}, + {0xec000030, "fres", {{21, 5, FREG}, {11, 5, FREG}}}, + {0xec000031, "fres.", {{21, 5, FREG}, {11, 5, FREG}}}, + {0xfc000018, "frsp", {{21, 5, FREG}, {11, 5, FREG}}}, + {0xfc000019, "frsp.", {{21, 5, FREG}, {11, 5, FREG}}}, + {0xfc000034, "frsqrte", {{21, 5, FREG}, {11, 5, FREG}}}, + {0xfc000035, "frsqrte.", {{21, 5, FREG}, {11, 5, FREG}}}, + {0xfc00002e, "fsel", {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}}, + {0xfc00002f, "fsel.", {{21, 5, FREG}, {16, 5, FREG}, {6, 5, FREG}, {11, 5, FREG}}}, + {0xfc00002c, "fsqrt", {{21, 5, FREG}, {11, 5, FREG}}, OPTIONAL | CPU970}, + {0xfc00002d, "fsqrt.", {{21, 5, FREG}, {11, 5, FREG}}, OPTIONAL | CPU970}, + {0xec00002c, "fsqrts", {{21, 5, FREG}, {11, 5, FREG}}, OPTIONAL | CPU970}, + {0xec00002d, "fsqrts.", {{21, 5, FREG}, {11, 5, FREG}}, OPTIONAL | CPU970}, + {0xfc00065c, "fctid", {{21, 5, FREG}, {11, 5, FREG}}, IMPL64}, + {0xfc00065d, "fctid.", {{21, 5, FREG}, {11, 5, FREG}}, IMPL64}, + {0xfc00065e, "fctidz", {{21, 5, FREG}, {11, 5, FREG}}, IMPL64}, + {0xfc00065f, "fctidz.", {{21, 5, FREG}, {11, 5, FREG}}, IMPL64}, + {0xfc00001c, "fctiw", {{21, 5, FREG}, {11, 5, FREG}}}, + {0xfc00001d, "fctiw.", {{21, 5, FREG}, {11, 5, FREG}}}, + {0xfc00001e, "fctiwz", {{21, 5, FREG}, {11, 5, FREG}}}, + {0xfc00001f, "fctiwz.", {{21, 5, FREG}, {11, 5, FREG}}}, + {0xfc00069c, "fcfid", {{21, 5, FREG}, {11, 5, FREG}}, IMPL64}, + {0xfc00069d, "fcfid.", {{21, 5, FREG}, {11, 5, FREG}}, IMPL64}, + + {0xfc000000, "fcmpu", {{21, 5, CRFONLY}, {16, 5, FREG}, {11, 5, FREG}}}, + {0xfc000000, "fcmpu", {{23, 3, NUM}, {16, 5, FREG}, {11, 5, FREG}}}, + {0xfc000040, "fcmpo", {{21, 5, CRFONLY}, {16, 5, FREG}, {11, 5, FREG}}}, + {0xfc000040, "fcmpo", {{23, 3, NUM}, {16, 5, FREG}, {11, 5, FREG}}}, + {0xfc00048e, "mffs", {{21, 5, FREG}}}, + {0xfc00048f, "mffs.", {{21, 5, FREG}}}, + {0xfc000080, "mcrfs", {{21, 5, CRFONLY}, {18, 5, NUM}}}, + {0xfc000080, "mcrfs", {{23, 3, NUM}, {18, 5, NUM}}}, + {0xfc00010c, "mtfsfi", {{23, 3, NUM}, {12, 4, NUM}}}, + {0xfc00010d, "mtfsfi.", {{23, 3, NUM}, {12, 4, NUM}}}, + {0xfc00058e, "mtfsf", {{17, 8, NUM}, {11, 5, FREG}}}, + {0xfc00058f, "mtfsf.", {{17, 8, NUM}, {11, 5, FREG}}}, + {0xfc00008c, "mtfsb0", {{21, 5, NUM}}}, + {0xfc00008d, "mtfsb0.", {{21, 5, NUM}}}, + {0xfc00004c, "mtfsb1", {{21, 5, NUM}}}, + {0xfc00004d, "mtfsb1.", {{21, 5, NUM}}}, + + {0x88000000, "lbz", {{21, 5, GREG}, {0, 16, D}, {16, 5, G0REG}}}, + {0x7c0000ae, "lbzx", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}}, + {0x8c000000, "lbzu", {{21, 5, GREG}, {0, 16, D}, {16, 5, G0REG}}}, + {0x7c0000ee, "lbzux", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0xa0000000, "lhz", {{21, 5, GREG}, {0, 16, D}, {16, 5, G0REG}}}, + {0x7c00022e, "lhzx", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}}, + {0xa4000000, "lhzu", {{21, 5, GREG}, {0, 16, D}, {16, 5, G0REG}}}, + {0x7c00026e, "lhzux", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0xa8000000, "lha", {{21, 5, GREG}, {0, 16, D}, {16, 5, G0REG}}}, + {0x7c0002ae, "lhax", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}}, + {0xac000000, "lhau", {{21, 5, GREG}, {0, 16, D}, {16, 5, GREG}}}, + {0x7c0002ee, "lhaux", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x80000000, "lwz", {{21, 5, GREG}, {0, 16, D}, {16, 5, G0REG}}}, + {0x7c00002e, "lwzx", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}}, + {0x84000000, "lwzu", {{21, 5, GREG}, {0, 16, D}, {16, 5, GREG}}}, + {0x7c00006e, "lwzux", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0xe8000002, "lwa", {{21, 5, GREG}, {2, 14, DS}, {16, 5, G0REG}}, IMPL64}, + {0x7c0002aa, "lwax", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}, IMPL64}, + {0x7c0002ea, "lwaux", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + {0xe8000000, "ld", {{21, 5, GREG}, {2, 14, DS}, {16, 5, G0REG}}, IMPL64}, + {0x7c00002a, "ldx", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}, IMPL64}, + {0xe8000001, "ldu", {{21, 5, GREG}, {2, 14, DS}, {16, 5, GREG}}, IMPL64}, + {0x7c00006a, "ldux", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + + {0xb8000000, "lmw", {{21, 5, GREG}, {0, 16, D}, {16, 5, G0REG}}}, + {0xbc000000, "stmw", {{21, 5, GREG}, {0, 16, D}, {16, 5, G0REG}}}, + + {0x7c00062c, "lhbrx", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}}, + {0x7c00042c, "lwbrx", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}}, + {0x7c00042a, "lswx", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}}, + {0x7c000028, "lwarx", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}}, + {0x7c0000a8, "ldarx", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}, IMPL64}, + + {0x7c00022a, "lscbx", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}, CPU601}, + {0x7c00022b, "lscbx.", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}, CPU601}, + + {0x7c0004aa, "lswi", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, NUM0}}}, + + {0xc0000000, "lfs", {{21, 5, FREG}, {0, 16, D}, {16, 5, G0REG}}}, + {0xc4000000, "lfsu", {{21, 5, FREG}, {0, 16, D}, {16, 5, GREG}}}, + {0x7c00042e, "lfsx", {{21, 5, FREG}, {16, 5, G0REG}, {11, 5, GREG}}}, + {0x7c00046e, "lfsux", {{21, 5, FREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0xc8000000, "lfd", {{21, 5, FREG}, {0, 16, D}, {16, 5, G0REG}}}, + {0xcc000000, "lfdu", {{21, 5, FREG}, {0, 16, D}, {16, 5, GREG}}}, + {0x7c0004ae, "lfdx", {{21, 5, FREG}, {16, 5, G0REG}, {11, 5, GREG}}}, + {0x7c0004ee, "lfdux", {{21, 5, FREG}, {16, 5, GREG}, {11, 5, GREG}}}, + + {0x38000000, "la", {{21, 5, GREG}, {0, 16, D}, {16, 5, G0REG}}}, + + {0x4c000000, "mcrf", {{21, 5, CRFONLY}, {16, 5, CRFONLY}}}, + {0x4c000000, "mcrf", {{23, 3, NUM}, {18, 3, NUM}}}, + + {0x7c0002a6, "mfspr", {{21, 5, GREG}, {11, 10, SPREG}}}, + {0x7c0003a6, "mtspr", {{11, 10, SPREG}, {21, 5, GREG}}}, + {0x7c000120, "mtcrf", {{12, 8, FXM}, {21, 5, GREG}}}, + {0x7c000120, "mtocrf", {{12, 8, FXM}, {21, 5, GREG}}}, + {0x7c000400, "mcrxr", {{21, 5, CRFONLY}}}, + {0x7c000400, "mcrxr", {{23, 3, NUM}}}, + {0x7c000026, "mfcr", {{21, 5, GREG}}}, + {0x7c100026, "mfcr", {{21, 5, GREG}, {12, 8, FXM}}}, + {0x7c100026, "mfocrf", {{21, 5, GREG}, {12, 8, FXM}}}, + + /* Move to/from spr mnemonics (assember extended mnemonics) */ + {0x7c0102a6, "mfxer", {{21, 5, GREG}}}, + {0x7c0802a6, "mflr", {{21, 5, GREG}}}, + {0x7c0902a6, "mfctr", {{21, 5, GREG}}}, + {0x7c0103a6, "mtxer", {{21, 5, GREG}}}, + {0x7c0803a6, "mtlr", {{21, 5, GREG}}}, + {0x7c0903a6, "mtctr", {{21, 5, GREG}}}, + {0x7c0002a6, "mfmq", {{21, 5, GREG}}}, + {0x7c0502a6, "mfrtcl", {{21, 5, GREG}}}, + {0x7c0402a6, "mfrtcu", {{21, 5, GREG}}}, + {0x7c0003a6, "mtmq", {{21, 5, GREG}}}, + {0x7c1503a6, "mtrtcl", {{21, 5, GREG}}}, + {0x7c1403a6, "mtrtcu", {{21, 5, GREG}}}, + +#ifdef NRW_COMPILER + {0x7c0001d6, "mull", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c0001d7, "mull.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c0005d6, "mullo", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c0005d7, "mullo.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, +#endif /* NRW_COMPILER */ + {0x7c0001d6, "mullw", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c0001d7, "mullw.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c0005d6, "mullwo", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c0005d7, "mullwo.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + + {0x7c000092, "mulhd", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + {0x7c000093, "mulhd.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + +#ifdef NRW_COMPILER + {0x7c000096, "mulwd", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000097, "mulwd.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, +#endif /* NRW_COMPILER */ + {0x7c000096, "mulhw", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000097, "mulhw.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + + {0x7c000012, "mulhdu", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + {0x7c000013, "mulhdu.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + + {0x7c000016, "mulhwu", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000017, "mulhwu.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + + {0x7c0001d2, "mulld", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + {0x7c0001d3, "mulld.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + {0x7c0005d2, "mulldo", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + {0x7c0005d3, "mulldo.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + + {0x7c0003b8, "nand", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}}, + {0x7c0003b9, "nand.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}}, + + {0x7c0000d0, "neg", {{21, 5, GREG}, {16, 5, GREG}}}, + {0x7c0000d1, "neg.", {{21, 5, GREG}, {16, 5, GREG}}}, + {0x7c0004d0, "nego", {{21, 5, GREG}, {16, 5, GREG}}}, + {0x7c0004d1, "nego.", {{21, 5, GREG}, {16, 5, GREG}}}, + + {0x7c0000f8, "nor", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}}, + {0x7c0000f9, "nor.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}}, + + /* Miscellaneous mnemonics (assember extended mnemonics) */ + { + 0x60000000, + "nop", + }, + + {0x60000000, "ori", {{16, 5, GREG}, {21, 5, GREG}, {0, 16, UI}}}, + {0x60000000, "ori", {{16, 5, ZERO}, {21, 5, ZERO}, {0, 16, ZERO}}}, + {0x64000000, "oris", {{16, 5, GREG}, {21, 5, GREG}, {0, 16, UI}}}, + {0x7c000378, "or", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}}, + {0x7c000379, "or.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}}, + + /// @brief Move register + {0x7c000378, "mr", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}}, + + {0x7c000338, "orc", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}}, + {0x7c000339, "orc.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}}, + + {0x78000000, "rldicl", {{16, 5, GREG}, {21, 5, GREG}, {0, 0, sh}, {0, 0, mb}}, IMPL64}, + {0x78000001, "rldicl.", {{16, 5, GREG}, {21, 5, GREG}, {0, 0, sh}, {0, 0, mb}}, IMPL64}, + {0x78000004, "rldicr", {{16, 5, GREG}, {21, 5, GREG}, {0, 0, sh}, {0, 0, mb}}, IMPL64}, + {0x78000005, "rldicr.", {{16, 5, GREG}, {21, 5, GREG}, {0, 0, sh}, {0, 0, mb}}, IMPL64}, + {0x78000008, "rldic", {{16, 5, GREG}, {21, 5, GREG}, {0, 0, sh}, {0, 0, mb}}, IMPL64}, + {0x78000009, "rldic.", {{16, 5, GREG}, {21, 5, GREG}, {0, 0, sh}, {0, 0, mb}}, IMPL64}, + {0x7800000c, "rldimi", {{16, 5, GREG}, {21, 5, GREG}, {0, 0, sh}, {0, 0, mb}}, IMPL64}, + {0x7800000d, "rldimi.", {{16, 5, GREG}, {21, 5, GREG}, {0, 0, sh}, {0, 0, mb}}, IMPL64}, + {0x78000010, "rldcl", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}, {0, 0, mb}}, IMPL64}, + {0x78000011, "rldcl.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}, {0, 0, mb}}, IMPL64}, + {0x78000012, "rldcr", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}, {0, 0, mb}}, IMPL64}, + {0x78000013, "rldcr.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}, {0, 0, mb}}, IMPL64}, + + {0x54000000, "rlwinm", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, NUM0}, {6, 5, MBE}, {1, 5, MBE}}}, + {0x54000001, + "rlwinm.", + {{16, 5, GREG}, {21, 5, GREG}, {11, 5, NUM0}, {6, 5, MBE}, {1, 5, MBE}}}, + {0x5c000000, "rlwnm", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}, {6, 5, MBE}, {1, 5, MBE}}}, + {0x5c000001, "rlwnm.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}, {6, 5, MBE}, {1, 5, MBE}}}, + {0x50000000, "rlwimi", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, NUM0}, {6, 5, MBE}, {1, 5, MBE}}}, + {0x50000001, + "rlwimi.", + {{16, 5, GREG}, {21, 5, GREG}, {11, 5, NUM0}, {6, 5, MBE}, {1, 5, MBE}}}, + + { + 0x44000002, + "sc", + }, + {0x4c000024, "rfid", {{0}}, IMPL64 | OPTIONAL}, + + {0x7c000030, "slw", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}}, + {0x7c000031, "slw.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}}, + {0x7c000036, "sld", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, IMPL64}, + {0x7c000037, "sld.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, IMPL64}, + + {0x7c000430, "srw", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}}, + {0x7c000431, "srw.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}}, + {0x7c000436, "srd", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, IMPL64}, + {0x7c000437, "srd.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, IMPL64}, + + {0x7c000670, "srawi", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, NUM}}}, + {0x7c000671, "srawi.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, NUM}}}, + {0x7c000674, "sradi", {{16, 5, GREG}, {21, 5, GREG}, {0, 0, sh}}, IMPL64}, + {0x7c000675, "sradi.", {{16, 5, GREG}, {21, 5, GREG}, {0, 0, sh}}, IMPL64}, + + {0x7c000630, "sraw", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}}, + {0x7c000631, "sraw.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}}, + {0x7c000634, "srad", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, IMPL64}, + {0x7c000635, "srad.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, IMPL64}, + + {0x98000000, "stb", {{21, 5, GREG}, {0, 16, D}, {16, 5, G0REG}}}, + {0x9c000000, "stbu", {{21, 5, GREG}, {0, 16, D}, {16, 5, GREG}}}, + {0x7c0001ae, "stbx", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}}, + {0x7c0001ee, "stbux", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0xb0000000, "sth", {{21, 5, GREG}, {0, 16, D}, {16, 5, G0REG}}}, + {0xb4000000, "sthu", {{21, 5, GREG}, {0, 16, D}, {16, 5, GREG}}}, + {0x7c00032e, "sthx", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}}, + {0x7c00036e, "sthux", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x90000000, "stw", {{21, 5, GREG}, {0, 16, D}, {16, 5, G0REG}}}, + {0x94000000, "stwu", {{21, 5, GREG}, {0, 16, D}, {16, 5, GREG}}}, + {0x7c00012e, "stwx", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}}, + {0x7c00016e, "stwux", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0xf8000000, "std", {{21, 5, GREG}, {2, 14, DS}, {16, 5, G0REG}}, IMPL64}, + {0xf8000001, "stdu", {{21, 5, GREG}, {2, 14, DS}, {16, 5, GREG}}, IMPL64}, + {0x7c00012a, "stdx", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}, IMPL64}, + {0x7c00016a, "stdux", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + + {0x7c00072c, "sthbrx", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}}, + {0x7c00052c, "stwbrx", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}}, + {0x7c00052a, "stswx", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}}, + {0x7c00012d, "stwcx.", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}}, + {0x7c0001ad, "stdcx.", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}, IMPL64}, + + {0x7c0005aa, "stswi", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, NUM0}}}, + + { + 0x7c0007ae, + "stfiwx", + {{21, 5, FREG}, {16, 5, G0REG}, {11, 5, GREG}}, + }, + + {0xd0000000, "stfs", {{21, 5, FREG}, {0, 16, D}, {16, 5, G0REG}}}, + {0xd4000000, "stfsu", {{21, 5, FREG}, {0, 16, D}, {16, 5, GREG}}}, + {0x7c00052e, "stfsx", {{21, 5, FREG}, {16, 5, G0REG}, {11, 5, GREG}}}, + {0x7c00056e, "stfsux", {{21, 5, FREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0xd8000000, "stfd", {{21, 5, FREG}, {0, 16, D}, {16, 5, G0REG}}}, + {0xdc000000, "stfdu", {{21, 5, FREG}, {0, 16, D}, {16, 5, GREG}}}, + {0x7c0005ae, "stfdx", {{21, 5, FREG}, {16, 5, G0REG}, {11, 5, GREG}}}, + {0x7c0005ee, "stfdux", {{21, 5, FREG}, {16, 5, GREG}, {11, 5, GREG}}}, + + {0x20000000, "subfic", {{21, 5, GREG}, {16, 5, GREG}, {0, 16, SI}}}, + {0x7c000050, "sub", {{21, 5, GREG}, {11, 5, GREG}, {16, 5, GREG}}}, + {0x7c000051, "sub.", {{21, 5, GREG}, {11, 5, GREG}, {16, 5, GREG}}}, + {0x7c000450, "subo", {{21, 5, GREG}, {11, 5, GREG}, {16, 5, GREG}}}, + {0x7c000451, "subo.", {{21, 5, GREG}, {11, 5, GREG}, {16, 5, GREG}}}, + {0x7c000050, "subf", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000051, "subf.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000450, "subfo", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000451, "subfo.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + + {0x7c000010, "subc", {{21, 5, GREG}, {11, 5, GREG}, {16, 5, GREG}}}, + {0x7c000011, "subc.", {{21, 5, GREG}, {11, 5, GREG}, {16, 5, GREG}}}, + {0x7c000410, "subco", {{21, 5, GREG}, {11, 5, GREG}, {16, 5, GREG}}}, + {0x7c000411, "subco.", {{21, 5, GREG}, {11, 5, GREG}, {16, 5, GREG}}}, + {0x7c000010, "subfc", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000011, "subfc.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000410, "subfco", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000411, "subfco.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + + {0x7c000110, "subfe", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000111, "subfe.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000510, "subfeo", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000511, "subfeo.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}}, + + {0x7c0001d0, "subfme", {{21, 5, GREG}, {16, 5, GREG}}}, + {0x7c0001d1, "subfme.", {{21, 5, GREG}, {16, 5, GREG}}}, + {0x7c0005d0, "subfmeo", {{21, 5, GREG}, {16, 5, GREG}}}, + {0x7c0005d1, "subfmeo.", {{21, 5, GREG}, {16, 5, GREG}}}, + + {0x7c000190, "subfze", {{21, 5, GREG}, {16, 5, GREG}}}, + {0x7c000191, "subfze.", {{21, 5, GREG}, {16, 5, GREG}}}, + {0x7c000590, "subfzeo", {{21, 5, GREG}, {16, 5, GREG}}}, + {0x7c000591, "subfzeo.", {{21, 5, GREG}, {16, 5, GREG}}}, + + { + 0x7c0004ac, + "sync", + }, + {0x7c0004ac, "sync", {{21, 2, NUM}}}, + { + 0x7c2004ac, + "lwsync", + }, + { + 0x7c4004ac, + "ptesync", + }, + + {0x08000000, "tdi", {{21, 5, NUM}, {16, 5, GREG}, {0, 16, SI}}, IMPL64}, + {0x0a000000, "tdlti", {{16, 5, GREG}, {0, 16, SI}}, IMPL64}, + {0x0a800000, "tdlei", {{16, 5, GREG}, {0, 16, SI}}, IMPL64}, + {0x08800000, "tdeqi", {{16, 5, GREG}, {0, 16, SI}}, IMPL64}, + {0x09800000, "tdgei", {{16, 5, GREG}, {0, 16, SI}}, IMPL64}, + {0x09000000, "tdgti", {{16, 5, GREG}, {0, 16, SI}}, IMPL64}, + {0x09800000, "tdnli", {{16, 5, GREG}, {0, 16, SI}}, IMPL64}, + {0x0b000000, "tdnei", {{16, 5, GREG}, {0, 16, SI}}, IMPL64}, + {0x0a800000, "tdngi", {{16, 5, GREG}, {0, 16, SI}}, IMPL64}, + {0x08400000, "tdllti", {{16, 5, GREG}, {0, 16, SI}}, IMPL64}, + {0x08c00000, "tdllei", {{16, 5, GREG}, {0, 16, SI}}, IMPL64}, + {0x08a00000, "tdlgei", {{16, 5, GREG}, {0, 16, SI}}, IMPL64}, + {0x08200000, "tdlgti", {{16, 5, GREG}, {0, 16, SI}}, IMPL64}, + {0x08a00000, "tdlnli", {{16, 5, GREG}, {0, 16, SI}}, IMPL64}, + {0x08c00000, "tdlngi", {{16, 5, GREG}, {0, 16, SI}}, IMPL64}, + + {0x7c000088, "td", {{21, 5, NUM}, {16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + {0x7e000088, "tdlt", {{16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + {0x7e800088, "tdle", {{16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + {0x7c800088, "tdeq", {{16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + {0x7d800088, "tdge", {{16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + {0x7d000088, "tdgt", {{16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + {0x7d800088, "tdnl", {{16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + {0x7f000088, "tdne", {{16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + {0x7e800088, "tdng", {{16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + {0x7c400088, "tdllt", {{16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + {0x7cc00088, "tdlle", {{16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + {0x7ca00088, "tdlge", {{16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + {0x7c200088, "tdlgt", {{16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + {0x7ca00088, "tdlnl", {{16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + {0x7cc00088, "tdlng", {{16, 5, GREG}, {11, 5, GREG}}, IMPL64}, + + {0x0c000000, "twi", {{21, 5, NUM}, {16, 5, GREG}, {0, 16, SI}}}, + {0x0e000000, "twlti", {{16, 5, GREG}, {0, 16, SI}}}, + {0x0e800000, "twlei", {{16, 5, GREG}, {0, 16, SI}}}, + {0x0c800000, "tweqi", {{16, 5, GREG}, {0, 16, SI}}}, + {0x0d800000, "twgei", {{16, 5, GREG}, {0, 16, SI}}}, + {0x0d000000, "twgti", {{16, 5, GREG}, {0, 16, SI}}}, + {0x0d800000, "twnli", {{16, 5, GREG}, {0, 16, SI}}}, + {0x0f000000, "twnei", {{16, 5, GREG}, {0, 16, SI}}}, + {0x0e800000, "twngi", {{16, 5, GREG}, {0, 16, SI}}}, + {0x0c400000, "twllti", {{16, 5, GREG}, {0, 16, SI}}}, + {0x0cc00000, "twllei", {{16, 5, GREG}, {0, 16, SI}}}, + {0x0ca00000, "twlgei", {{16, 5, GREG}, {0, 16, SI}}}, + {0x0c200000, "twlgti", {{16, 5, GREG}, {0, 16, SI}}}, + {0x0ca00000, "twlnli", {{16, 5, GREG}, {0, 16, SI}}}, + {0x0cc00000, "twlngi", {{16, 5, GREG}, {0, 16, SI}}}, + + {0x7c000008, "tw", {{21, 5, NUM}, {16, 5, GREG}, {11, 5, GREG}}}, + {0x7c000008, "tw", {{21, 5, NUM}, {16, 5, ZERO}, {11, 5, ZERO}}}, + {0x7e000008, "twlt", {{16, 5, GREG}, {11, 5, GREG}}}, + {0x7e800008, "twle", {{16, 5, GREG}, {11, 5, GREG}}}, + {0x7c800008, "tweq", {{16, 5, GREG}, {11, 5, GREG}}}, + {0x7d800008, "twge", {{16, 5, GREG}, {11, 5, GREG}}}, + {0x7d000008, "twgt", {{16, 5, GREG}, {11, 5, GREG}}}, + {0x7d800008, "twnl", {{16, 5, GREG}, {11, 5, GREG}}}, + {0x7f000008, "twne", {{16, 5, GREG}, {11, 5, GREG}}}, + {0x7e800008, "twng", {{16, 5, GREG}, {11, 5, GREG}}}, + {0x7c400008, "twllt", {{16, 5, GREG}, {11, 5, GREG}}}, + {0x7cc00008, "twlle", {{16, 5, GREG}, {11, 5, GREG}}}, + {0x7ca00008, "twlge", {{16, 5, GREG}, {11, 5, GREG}}}, + {0x7c200008, "twlgt", {{16, 5, GREG}, {11, 5, GREG}}}, + {0x7ca00008, "twlnl", {{16, 5, GREG}, {11, 5, GREG}}}, + {0x7cc00008, "twlng", {{16, 5, GREG}, {11, 5, GREG}}}, + { + 0x7fe00008, + "trap", + }, + + {0x68000000, "xori", {{16, 5, GREG}, {21, 5, GREG}, {0, 16, UI}}}, + {0x6c000000, "xoris", {{16, 5, GREG}, {21, 5, GREG}, {0, 16, UI}}}, + {0x7c000278, "xor", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}}, + {0x7c000279, "xor.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}}, + + /* Cache Management Instructions (from book II) */ + {0x7c0007ac, "icbi", {{16, 5, G0REG}, {11, 5, GREG}}}, + { + 0x4c00012c, + "isync", + }, + {0x7c00022c, "dcbt", {{16, 5, G0REG}, {11, 5, GREG}}}, + { + 0x7c00022c, + "dcbt", + {{16, 5, G0REG}, {11, 5, GREG}, {21, 4, NUM}}, + }, + {0x7c0001ec, "dcbtst", {{16, 5, G0REG}, {11, 5, GREG}}}, + {0x7c00022c, "dcbt128", {{16, 5, G0REG}, {11, 5, GREG}, {21, 4, NUM}}, IMPL64 | OPTIONAL}, + {0x7c0007ec, "dcbz", {{16, 5, G0REG}, {11, 5, GREG}}}, + {0x7c2007ec, "dcbzl", {{16, 5, G0REG}, {11, 5, GREG}}}, + {0x7c2007ec, "dcbz128", {{16, 5, G0REG}, {11, 5, GREG}}, IMPL64 | OPTIONAL}, + {0x7c00006c, "dcbst", {{16, 5, G0REG}, {11, 5, GREG}}}, + {0x7c0000ac, "dcbf", {{16, 5, G0REG}, {11, 5, GREG}}}, + {0x7c00026c, "eciwx", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}, OPTIONAL | CPU970}, + {0x7c00036c, "ecowx", {{21, 5, GREG}, {16, 5, G0REG}, {11, 5, GREG}}, OPTIONAL | CPU970}, + { + 0x7c0006ac, + "eieio", + }, + /* Instructions (from book III) */ + { + 0x4c000064, + "rfi", + }, + {0x7c000124, "mtmsr", {{21, 5, GREG}}}, + {0x7c000164, "mtmsrd", {{21, 5, GREG}}, IMPL64 | OPTIONAL}, + {0x7c000164, "mtmsrd", {{21, 5, GREG}, {16, 1, NUM}}, IMPL64 | OPTIONAL}, + {0x7c0000a6, "mfmsr", {{21, 5, GREG}}}, + {0x7c0005ec, "dcba", {{16, 5, G0REG}, {11, 5, GREG}}, OPTIONAL}, + {0x7c0003ac, "dcbi", {{16, 5, G0REG}, {11, 5, GREG}}}, + {0x7c0001a4, "mtsr", {{16, 4, SGREG}, {21, 5, GREG}}}, + {0x7c0004a6, "mfsr", {{21, 5, GREG}, {16, 4, SGREG}}}, + {0x7c0001e4, "mtsrin", {{21, 5, GREG}, {11, 5, GREG}}}, + {0x7c000526, "mfsrin", {{21, 5, GREG}, {11, 5, GREG}}}, + {0x7c000364, "slbie", {{11, 5, GREG}}, IMPL64 | OPTIONAL}, + {0x7c0003e4, "slbia", {{0}}, IMPL64 | OPTIONAL}, + {0x7c000324, "slbmte", {{21, 5, GREG}, {11, 5, GREG}}, IMPL64 | OPTIONAL}, + {0x7c0006a6, "slbmfev", {{21, 5, GREG}, {11, 5, GREG}}, IMPL64 | OPTIONAL}, + {0x7c000726, "slbmfee", {{21, 5, GREG}, {11, 5, GREG}}, IMPL64 | OPTIONAL}, + {0x7c000264, "tlbie", {{11, 5, GREG}}, OPTIONAL | CPU970}, + {0x7c000264, "tlbie", {{11, 5, GREG}, {21, 1, NUM}}, IMPL64 | OPTIONAL | CPU970}, + {0x7c000224, "tlbiel", {{11, 5, GREG}}, IMPL64 | OPTIONAL}, + {0x7c0002e4, "tlbia", {{0}}, OPTIONAL | CPU970}, + {0x7c00046c, "tlbsync", {{0}}, OPTIONAL | CPU970}, + {0x7c1c43a6, "mttbl", {{21, 5, GREG}}}, + {0x7c1d43a6, "mttbu", {{21, 5, GREG}}}, + {0x7c0002e6, "mftb", {{21, 5, GREG}, {11, 10, SPREG}}}, + {0x7c0c42e6, "mftb", {{21, 5, GREG}}}, + {0x7c0d42e6, "mftbu", {{21, 5, GREG}}}, + {0x00000200, "attn", {{11, 15, NUM}}, OPTIONAL | CPU970}, + + /* Instructions (from book IV) */ + {0x24000000, "dozi", {{21, 5, GREG}, {16, 5, GREG}, {0, 16, SI}}, CPU601}, + {0x7c000210, "doz", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, CPU601}, + {0x7c000211, "doz.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, CPU601}, + {0x7c000610, "dozo", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, CPU601}, + {0x7c000611, "dozo.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, CPU601}, + + {0x7c0002d0, "abs", {{21, 5, GREG}, {16, 5, GREG}}, CPU601}, + {0x7c0002d1, "abs.", {{21, 5, GREG}, {16, 5, GREG}}, CPU601}, + {0x7c0006d0, "abso", {{21, 5, GREG}, {16, 5, GREG}}, CPU601}, + {0x7c0006d1, "abso.", {{21, 5, GREG}, {16, 5, GREG}}, CPU601}, + + {0x7c0003d0, "nabs", {{21, 5, GREG}, {16, 5, GREG}}, CPU601}, + {0x7c0003d1, "nabs.", {{21, 5, GREG}, {16, 5, GREG}}, CPU601}, + {0x7c0007d0, "nabso", {{21, 5, GREG}, {16, 5, GREG}}, CPU601}, + {0x7c0007d1, "nabso.", {{21, 5, GREG}, {16, 5, GREG}}, CPU601}, + + {0x1c000000, "mulli", {{21, 5, GREG}, {16, 5, GREG}, {0, 16, SI}}}, + + {0x7c0000d6, "mul", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, CPU601}, + {0x7c0000d7, "mul.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, CPU601}, + {0x7c0004d6, "mulo", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, CPU601}, + {0x7c0004d7, "mulo.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, CPU601}, + + {0x7c000296, "div", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, CPU601}, + {0x7c000297, "div.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, CPU601}, + {0x7c000696, "divo", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, CPU601}, + {0x7c000697, "divo.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, CPU601}, + + {0x7c0002d6, "divs", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, CPU601}, + {0x7c0002d7, "divs.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, CPU601}, + {0x7c0006d6, "divso", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, CPU601}, + {0x7c0006d7, "divso.", {{21, 5, GREG}, {16, 5, GREG}, {11, 5, GREG}}, CPU601}, + + {0x58000000, + "rlmi", + {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}, {6, 5, MBE}, {1, 5, MBE}}, + CPU601}, + {0x58000001, + "rlmi.", + {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}, {6, 5, MBE}, {1, 5, MBE}}, + CPU601}, + + {0x7c000432, "rrib", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601}, + {0x7c000433, "rrib.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601}, + + {0x7c00003a, "maskg", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601}, + {0x7c00003b, "maskg.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601}, + + {0x7c00043a, "maskir", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601}, + {0x7c00043b, "maskir.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601}, + + {0x7c000130, "slq", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601}, + {0x7c000131, "slq.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601}, + + {0x7c000530, "srq", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601}, + {0x7c000531, "srq.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601}, + + {0x7c000170, "sliq", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, NUM}}, CPU601}, + {0x7c000171, "sliq.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, NUM}}, CPU601}, + + {0x7c000570, "sriq", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, NUM}}, CPU601}, + {0x7c000571, "sriq.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, NUM}}, CPU601}, + + {0x7c0001f0, "slliq", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, NUM}}, CPU601}, + {0x7c0001f1, "slliq.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, NUM}}, CPU601}, + + {0x7c0005f0, "srliq", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, NUM}}, CPU601}, + {0x7c0005f1, "srliq.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, NUM}}, CPU601}, + + {0x7c0001b0, "sllq", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601}, + {0x7c0001b1, "sllq.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601}, + + {0x7c0005b0, "srlq", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601}, + {0x7c0005b1, "srlq.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601}, + + {0x7c000132, "sle", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601}, + {0x7c000133, "sle.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601}, + + {0x7c000532, "sre", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601}, + {0x7c000533, "sre.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601}, + + {0x7c0001b2, "sleq", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601}, + {0x7c0001b3, "sleq.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601}, + + {0x7c0005b2, "sreq", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601}, + {0x7c0005b3, "sreq.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601}, + + {0x7c000770, "sraiq", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, NUM}}, CPU601}, + {0x7c000771, "sraiq.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, NUM}}, CPU601}, + + {0x7c000730, "sraq", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601}, + {0x7c000731, "sraq.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601}, + + {0x7c000732, "srea", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601}, + {0x7c000733, "srea.", {{16, 5, GREG}, {21, 5, GREG}, {11, 5, GREG}}, CPU601}, + + /* Added from the POWER 601 book */ + {0x7c000426, "clcs", {{21, 5, GREG}, {16, 5, GREG}}, CPU601}, + + /* Added from the POWER 603 book. + * These are really 603 specific instructions but we mark them as OPTIONAL + * so that the -force_cpusubtype_ALL flag as to be used. This makes it so + * only 601 instructions will cause the cputype to be set to other an ALL. + */ + {0x7c0007a4, "tlbld", {{11, 5, GREG}}, OPTIONAL}, + {0x7c0007e4, "tlbli", {{11, 5, GREG}}, OPTIONAL}, + + /* VMX Instructions */ + {0x7c00000e, "lvebx", {{21, 5, VREG}, {16, 5, G0REG}, {11, 5, GREG}}, VMX}, + {0x7c00004e, "lvehx", {{21, 5, VREG}, {16, 5, G0REG}, {11, 5, GREG}}, VMX}, + {0x7c00008e, "lvewx", {{21, 5, VREG}, {16, 5, G0REG}, {11, 5, GREG}}, VMX}, + {0x7c0000ce, "lvx", {{21, 5, VREG}, {16, 5, G0REG}, {11, 5, GREG}}, VMX}, + {0x7c0002ce, "lvxl", {{21, 5, VREG}, {16, 5, G0REG}, {11, 5, GREG}}, VMX}, + + {0x7c00010e, "stvebx", {{21, 5, VREG}, {16, 5, G0REG}, {11, 5, GREG}}, VMX}, + {0x7c00014e, "stvehx", {{21, 5, VREG}, {16, 5, G0REG}, {11, 5, GREG}}, VMX}, + {0x7c00018e, "stvewx", {{21, 5, VREG}, {16, 5, G0REG}, {11, 5, GREG}}, VMX}, + {0x7c0001ce, "stvx", {{21, 5, VREG}, {16, 5, G0REG}, {11, 5, GREG}}, VMX}, + {0x7c0003ce, "stvxl", {{21, 5, VREG}, {16, 5, G0REG}, {11, 5, GREG}}, VMX}, + + {0x7c00000c, "lvsl", {{21, 5, VREG}, {16, 5, G0REG}, {11, 5, GREG}}, VMX}, + {0x7c00004c, "lvsr", {{21, 5, VREG}, {16, 5, G0REG}, {11, 5, GREG}}, VMX}, + + {0x10000644, "mtvscr", {{11, 5, VREG}}, VMX}, + {0x10000604, "mfvscr", {{21, 5, VREG}}, VMX}, + + {0x7c0002ac, "dst", {{16, 5, GREG}, {11, 5, GREG}, {21, 2, NUM}}, VMX}, + {0x7e0002ac, "dstt", {{16, 5, GREG}, {11, 5, GREG}, {21, 2, NUM}}, VMX}, + {0x7c0002ec, "dstst", {{16, 5, GREG}, {11, 5, GREG}, {21, 2, NUM}}, VMX}, + {0x7e0002ec, "dststt", {{16, 5, GREG}, {11, 5, GREG}, {21, 2, NUM}}, VMX}, + {0x7c00066c, "dss", {{21, 2, NUM}}, VMX}, + {0x7e00066c, "dssall", {{0}}, VMX}, + + {0x10000000, "vaddubm", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000200, "vaddubs", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000300, "vaddsbs", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000040, "vadduhm", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000240, "vadduhs", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000340, "vaddshs", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000080, "vadduwm", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000280, "vadduws", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000380, "vaddsws", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x1000000a, "vaddfp", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + + {0x10000180, "vaddcuw", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + + {0x10000400, "vsububm", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000600, "vsububs", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000700, "vsubsbs", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000440, "vsubuhm", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000640, "vsubuhs", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000740, "vsubshs", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000480, "vsubuwm", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000680, "vsubuws", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000780, "vsubsws", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x1000004a, "vsubfp", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + + {0x10000580, "vsubcuw", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + + {0x10000008, "vmuloub", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000108, "vmulosb", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000048, "vmulouh", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000148, "vmulosh", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + + {0x10000208, "vmuleub", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000308, "vmulesb", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000248, "vmuleuh", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000348, "vmulesh", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + + {0x10000020, "vmhaddshs", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}, {6, 5, VREG}}, VMX}, + {0x10000021, "vmhraddshs", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}, {6, 5, VREG}}, VMX}, + {0x10000022, "vmladduhm", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}, {6, 5, VREG}}, VMX}, + {0x1000002e, "vmaddfp", {{21, 5, VREG}, {16, 5, VREG}, {6, 5, VREG}, {11, 5, VREG}}, VMX}, + + {0x10000024, "vmsumubm", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}, {6, 5, VREG}}, VMX}, + {0x10000025, "vmsummbm", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}, {6, 5, VREG}}, VMX}, + {0x10000026, "vmsumuhm", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}, {6, 5, VREG}}, VMX}, + {0x10000027, "vmsumuhs", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}, {6, 5, VREG}}, VMX}, + {0x10000028, "vmsumshm", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}, {6, 5, VREG}}, VMX}, + {0x10000029, "vmsumshs", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}, {6, 5, VREG}}, VMX}, + + {0x10000788, "vsumsws", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + + {0x10000688, "vsum2sws", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + + {0x10000608, "vsum4ubs", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000708, "vsum4sbs", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000648, "vsum4shs", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + + {0x10000402, "vavgub", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000442, "vavguh", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000482, "vavguw", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000502, "vavgsb", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000542, "vavgsh", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000582, "vavgsw", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + + {0x10000404, "vand", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000484, "vor", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x100004c4, "vxor", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000444, "vandc", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000504, "vnor", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + + {0x10000004, "vrlb", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000044, "vrlh", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000084, "vrlw", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + + {0x10000104, "vslb", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000144, "vslh", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000184, "vslw", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x100001c4, "vsl", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + + {0x10000204, "vsrb", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000304, "vsrab", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000244, "vsrh", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000344, "vsrah", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000284, "vsrw", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000384, "vsraw", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x100002c4, "vsr", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + + {0x10000206, "vcmpgtub", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000606, "vcmpgtub.", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000306, "vcmpgtsb", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000706, "vcmpgtsb.", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000246, "vcmpgtuh", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000646, "vcmpgtuh.", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000346, "vcmpgtsh", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000746, "vcmpgtsh.", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000286, "vcmpgtuw", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000686, "vcmpgtuw.", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000386, "vcmpgtsw", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000786, "vcmpgtsw.", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x100002c6, "vcmpgtfp", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x100006c6, "vcmpgtfp.", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + + {0x10000006, "vcmpequb", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000406, "vcmpequb.", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000046, "vcmpequh", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000446, "vcmpequh.", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000086, "vcmpequw", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000486, "vcmpequw.", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x100000c6, "vcmpeqfp", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x100004c6, "vcmpeqfp.", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + + {0x100001c6, "vcmpgefp", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x100005c6, "vcmpgefp.", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + + {0x100003c6, "vcmpbfp", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x100007c6, "vcmpbfp.", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + + {0x1000002a, "vsel", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}, {6, 5, VREG}}, VMX}, + + {0x1000000e, "vpkuhum", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x1000008e, "vpkuhus", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x1000010e, "vpkshus", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x1000018e, "vpkshss", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x1000004e, "vpkuwum", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x100000ce, "vpkuwus", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x1000014e, "vpkswus", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x100001ce, "vpkswss", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x1000030e, "vpkpx", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + + {0x1000020e, "vupkhsb", {{21, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x1000024e, "vupkhsh", {{21, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x1000034e, "vupkhpx", {{21, 5, VREG}, {11, 5, VREG}}, VMX}, + + {0x1000028e, "vupklsb", {{21, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x100002ce, "vupklsh", {{21, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x100003ce, "vupklpx", {{21, 5, VREG}, {11, 5, VREG}}, VMX}, + + {0x1000000c, "vmrghb", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x1000004c, "vmrghh", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x1000008c, "vmrghw", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + + {0x1000010c, "vmrglb", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x1000014c, "vmrglh", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x1000018c, "vmrglw", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + + {0x1000020c, "vspltb", {{21, 5, VREG}, {11, 5, VREG}, {16, 5, NUM}}, VMX}, + {0x1000024c, "vsplth", {{21, 5, VREG}, {11, 5, VREG}, {16, 5, NUM}}, VMX}, + {0x1000028c, "vspltw", {{21, 5, VREG}, {11, 5, VREG}, {16, 5, NUM}}, VMX}, + + {0x1000030c, "vspltisb", {{21, 5, VREG}, {16, 5, SNUM}}, VMX}, + {0x1000034c, "vspltish", {{21, 5, VREG}, {16, 5, SNUM}}, VMX}, + {0x1000038c, "vspltisw", {{21, 5, VREG}, {16, 5, SNUM}}, VMX}, + + {0x1000002b, "vperm", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}, {6, 5, VREG}}, VMX}, + + {0x1000002c, "vsldoi", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}, {6, 4, NUM}}, VMX}, + + {0x1000040c, "vslo", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x1000044c, "vsro", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + + {0x10000002, "vmaxub", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000102, "vmaxsb", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000042, "vmaxuh", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000142, "vmaxsh", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000082, "vmaxuw", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000182, "vmaxsw", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x1000040a, "vmaxfp", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + + {0x10000202, "vminub", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000302, "vminsb", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000242, "vminuh", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000342, "vminsh", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000282, "vminuw", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x10000382, "vminsw", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x1000044a, "vminfp", {{21, 5, VREG}, {16, 5, VREG}, {11, 5, VREG}}, VMX}, + + {0x1000010a, "vrefp", {{21, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x1000014a, "vrsqrtefp", {{21, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x100001ca, "vlogefp", {{21, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x1000018a, "vexptefp", {{21, 5, VREG}, {11, 5, VREG}}, VMX}, + + {0x1000002f, "vnmsubfp", {{21, 5, VREG}, {16, 5, VREG}, {6, 5, VREG}, {11, 5, VREG}}, VMX}, + + {0x1000020a, "vrfin", {{21, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x1000024a, "vrfiz", {{21, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x1000028a, "vrfip", {{21, 5, VREG}, {11, 5, VREG}}, VMX}, + {0x100002ca, "vrfim", {{21, 5, VREG}, {11, 5, VREG}}, VMX}, + + {0x1000038a, "vctuxs", {{21, 5, VREG}, {11, 5, VREG}, {16, 5, NUM}}, VMX}, + {0x100003ca, "vctsxs", {{21, 5, VREG}, {11, 5, VREG}, {16, 5, NUM}}, VMX}, + + {0x1000030a, "vcfux", {{21, 5, VREG}, {11, 5, VREG}, {16, 5, NUM}}, VMX}, + {0x1000034a, "vcfsx", {{21, 5, VREG}, {11, 5, VREG}, {16, 5, NUM}}, VMX}, + + {0, ""} /* end of table marker */ +}; + +#define kAsmFloatZeroRegister 0 +#define kAsmZeroRegister 0 + +#define kAsmRegisterPrefix "r" +#define kAsmRegisterLimit 31 +#define kAsmPcRegister 17 +#define kAsmCrRegister 18 +#define kAsmSpRegister 5 + +/* return address register */ +#define kAsmRetRegister 19 diff --git a/include/CompilerKit/Detail/PreConfig.h b/include/CompilerKit/Detail/PreConfig.h new file mode 100644 index 0000000..6742c53 --- /dev/null +++ b/include/CompilerKit/Detail/PreConfig.h @@ -0,0 +1,120 @@ +/* ======================================== + + Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license + +======================================== */ + +#pragma once + +#ifndef Yes +#define Yes true +#endif // ifndef Yes + +#ifndef No +#define No false +#endif // ifndef No + +#ifndef YES +#define YES true +#endif // ifndef YES + +#ifndef NO +#define NO false +#endif // ifndef NO + +#define SizeType size_t + +#define VoidPtr void* +#define voidPtr VoidPtr + +#define UIntPtr uintptr_t + +#define Int64 int64_t +#define UInt64 uint64_t + +#define Int32 int +#define UInt32 unsigned + +#define Int16 int16_t +#define UInt16 uint16_t + +#define Int8 int8_t +#define UInt8 uint8_t + +#define Char char + +#include <signal.h> +#include <stdint.h> +#include <time.h> +#include <unistd.h> +#include <cassert> +#include <string> + +#define kDistVersion "v0.0.7-compilerkit" +#define kDistVersionBCD 0x0002 + +#define ToString(X) Stringify(X) +#define Stringify(X) #X + +#define kDistRelease ToString(kDistReleaseBranch) + +#ifndef kDistRelease + +#define kDistVersion "v0.0.7-compilerkit" +#define kDistVersionBCD 0x0002 + +#define ToString(X) Stringify(X) +#define Stringify(X) #X + +#define kDistRelease ToString(kDistReleaseBranch) + +#endif // !kDistRelease + +#define MUST_PASS(E) assert(E) + +#ifndef __FORCE_STRLEN +#define __FORCE_STRLEN 1 + +#define string_length(len) strlen(len) +#endif + +#ifndef __FORCE_MEMCPY +#define __FORCE_MEMCPY 1 + +#define rt_copy_memory(dst, src, len) memcpy(dst, src, len) +#endif + +#define ATTRIBUTE(X) __attribute__((X)) +#define PACKED ATTRIBUTE(packed) + +#define kObjectFileExt ".obj" +#define kBinaryFileExt ".bin" + +#define kAsmFileExts {".64x", ".32x", ".masm", ".s", ".S", ".asm", ".x64"} + +#define kAsmFileExtsMax (7U) + +#define NECTI_MODULE(name) extern "C" int name(int argc, char** argv) + +#ifdef MSVC +#pragma scalar_storage_order big - endian +#endif // ifdef MSVC + +#define NECTI_COPY_DELETE(KLASS) \ + KLASS& operator=(const KLASS&) = delete; \ + KLASS(const KLASS&) = delete; + +#define NECTI_COPY_DEFAULT(KLASS) \ + KLASS& operator=(const KLASS&) = default; \ + KLASS(const KLASS&) = default; + +#define NECTI_MOVE_DELETE(KLASS) \ + KLASS& operator=(KLASS&&) = delete; \ + KLASS(KLASS&&) = delete; + +#define NECTI_MOVE_DEFAULT(KLASS) \ + KLASS& operator=(KLASS&&) = default; \ + KLASS(KLASS&&) = default; + +#define CK_IMPORT_C extern "C" +#define CK_IMPORT extern diff --git a/include/CompilerKit/ErrorID.h b/include/CompilerKit/ErrorID.h new file mode 100644 index 0000000..3e3b0d7 --- /dev/null +++ b/include/CompilerKit/ErrorID.h @@ -0,0 +1,29 @@ +/* + * ======================================================== + * + * CompilerKit + * Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. + * + * ======================================================== + */ + +#pragma once + +#include <CompilerKit/Detail/Config.h> + +/// =========================================================== /// +/// @file ErrorID.h +/// @author Amlal El Mahrouss +/// @brief Error IDs for CompilerKit. +/// =========================================================== /// + +#define NECTI_SUCCESS 0 +#define NECTI_EXEC_ERROR -30 +#define NECTI_FILE_NOT_FOUND -31 +#define NECTI_DIR_NOT_FOUND -32 +#define NECTI_FILE_EXISTS -33 +#define NECTI_TOO_LONG -34 +#define NECTI_INVALID_DATA -35 +#define NECTI_UNIMPLEMENTED -36 +#define NECTI_FAT_ERROR -37 +#define NECTI_INVALID_ARCH -38 diff --git a/include/CompilerKit/ErrorOr.h b/include/CompilerKit/ErrorOr.h new file mode 100644 index 0000000..100624e --- /dev/null +++ b/include/CompilerKit/ErrorOr.h @@ -0,0 +1,54 @@ +/* + * ======================================================== + * + * CompilerKit + * Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. + * + * ======================================================== + */ + +#pragma once + +/// =========================================================== /// +/// @file ErrorOr.h +/// @author Amlal El Mahrouss +/// @brief ErrorOr for CompilerKit. +/// =========================================================== /// + +#include <CompilerKit/Detail/Config.h> +#include <CompilerKit/ErrorID.h> +#include <CompilerKit/Ref.h> + +namespace CompilerKit { +using ErrorT = Int32; + +template <typename T> +class ErrorOr final { + public: + ErrorOr() = default; + ~ErrorOr() = default; + + public: + explicit ErrorOr(ErrorT err) : mId(err) {} + explicit ErrorOr(std::nullptr_t null) {} + explicit ErrorOr(T klass) : mRef(klass) {} + + ErrorOr& operator=(const ErrorOr&) = default; + ErrorOr(const ErrorOr&) = default; + + Ref<T>& Leak() { return mRef; } + + ErrorT Error() { return mId; } + + bool HasError() { return mId != NECTI_SUCCESS; } + + explicit operator bool() { return mRef; } + + private: + Ref<T> mRef; + ErrorT mId{0}; +}; + +using ErrorOrAny = ErrorOr<VoidPtr>; +using ErrorOrString = ErrorOr<STLString>; +} // namespace CompilerKit diff --git a/include/CompilerKit/Macros.h b/include/CompilerKit/Macros.h new file mode 100644 index 0000000..6cef758 --- /dev/null +++ b/include/CompilerKit/Macros.h @@ -0,0 +1,28 @@ +/* ======================================== + + Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license + +======================================== */ + +/// @brief provide support for Macros.h header. + +#ifndef _NECTI_MACROS_H_ +#define _NECTI_MACROS_H_ + +#define NECTI_COPY_DELETE(KLASS) \ + KLASS& operator=(const KLASS&) = delete; \ + KLASS(const KLASS&) = delete; + +#define NECTI_COPY_DEFAULT(KLASS) \ + KLASS& operator=(const KLASS&) = default; \ + KLASS(const KLASS&) = default; + +#define NECTI_MOVE_DELETE(KLASS) \ + KLASS& operator=(KLASS&&) = delete; \ + KLASS(KLASS&&) = delete; + +#define NECTI_MOVE_DEFAULT(KLASS) \ + KLASS& operator=(KLASS&&) = default; \ + KLASS(KLASS&&) = default; + +#endif /* ifndef _NECTI_MACROS_H_ */ diff --git a/include/CompilerKit/PEF.h b/include/CompilerKit/PEF.h new file mode 100644 index 0000000..2838f52 --- /dev/null +++ b/include/CompilerKit/PEF.h @@ -0,0 +1,138 @@ +/* ========================================= + + Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license + +======================================== */ + +#pragma once + +#include <CompilerKit/Detail/Config.h> +#include <fstream> + +// @file PEF.h +// @brief Preferred Executable Format + +#define kPefMagic "Open" +#define kPefMagicFat "nepO" + +#define kPefExt ".exec" +#define kPefDylibExt ".dylib" +#define kPefLibExt ".lib" +#define kPefObjectExt ".obj" +#define kPefDebugExt ".dbg" +#define kPefDriverExt ".sys" + +#define kPefZero128 ".zero128" +#define kPefCode128 ".code128" +#define kPefData128 ".data128" + +#define kPefZero64 ".zero64" +#define kPefCode64 ".code64" +#define kPefData64 ".data64" + +/* @note counting the \0 at the end */ +#define kPefMagicLen (5) + +#define kPefVersion (0x0500) +#define kPefNameLen (255) + +#define kPefBaseOrigin (0x40000000) + +/* @note this doesn't have to be __ImageStart only, any C initialization stub will do. */ +#define kPefStart "__ImageStart" + +namespace CompilerKit { +/* @brief Architecture type. */ +enum { + kPefArchIntel86S, + kPefArchAMD64, + kPefArchRISCV, + kPefArch64000, /* Open64x0 RISC architecture. */ + kPefArch32000, + kPefArchPowerPC, /* 64-bit POWER architecture. */ + kPefArchARM64, + kPefArchCount = (kPefArchARM64 - kPefArchIntel86S) + 1, + kPefArchInvalid = 0xFF, +}; + +/* @brief Architecture vendor. */ +enum { + kPefSubArchGeneric = 0, + kPefSubArchAMD = 200, + kPefSubArchIntel, + kPefSubArchARM, + kPefSubArchIBM, +}; + +enum { + kPefKindInvalid = 0, + kPefKindExec = 1, /* .exec */ + kPefKindDylib = 2, /* .dylib */ + kPefKindObject = 4, /* .obj */ + kPefKindDebug = 5, /* .dbg */ + kPefKindDriver = 6, + kPefKindCount, +}; + +/* PEF container information */ +typedef struct PEFContainer final { + Char Magic[kPefMagicLen]; + UInt32 Linker; /* Linker used to link executable */ + UInt32 Version; + UInt32 Kind; + UInt32 Abi; + UInt32 Cpu; + UInt32 SubCpu; /* Cpu specific information */ + UIntPtr Start; /* Origin of code */ + SizeType HdrSz; /* Size of header */ + SizeType Count; /* container header count */ + UInt32 Checksum; /* Whole binary checksum */ +} PACKED PEFContainer, *PEFContainerPtr; + +/* First PEFCommandHeader starts after PEFContainer */ +/* Last container is __exec_end */ + +/* PEF executable section and commands. */ + +/* @brief Command Header, a la Mach-O, designed with FAT binaries and virtual memory in mind. */ +typedef struct PEFCommandHeader final { + Char Name[kPefNameLen]; /* container name */ + UInt32 Cpu; /* container cpu */ + UInt32 SubCpu; /* container sub-cpu */ + UInt32 Flags; /* container flags */ + UInt16 Kind; /* container kind */ + UIntPtr Offset; /* File offset */ + SizeType OffsetSize; + UIntPtr VirtualAddress; /* Virtual Address */ + SizeType VirtualSize; /* Virtual Size */ +} PACKED PEFCommandHeader, *PEFCommandHeaderPtr; + +enum { + kPefInvalid = 0x0, + kPefCode = 0xC, + kPefData = 0xD, + kPefZero = 0xE, + kPefLinkerID = 0x1, + kPefCount = 4, +}; +} // namespace CompilerKit + +inline std::ofstream& operator<<(std::ofstream& fp, CompilerKit::PEFContainer& container) { + fp.write((char*) &container, sizeof(CompilerKit::PEFContainer)); + return fp; +} + +inline std::ofstream& operator<<(std::ofstream& fp, CompilerKit::PEFCommandHeader& container) { + fp.write((char*) &container, sizeof(CompilerKit::PEFCommandHeader)); + return fp; +} + +inline std::ifstream& operator>>(std::ifstream& fp, CompilerKit::PEFContainer& container) { + fp.read((char*) &container, sizeof(CompilerKit::PEFContainer)); + return fp; +} + +inline std::ifstream& operator>>(std::ifstream& fp, CompilerKit::PEFCommandHeader& container) { + fp.read((char*) &container, sizeof(CompilerKit::PEFCommandHeader)); + return fp; +} diff --git a/include/CompilerKit/Ref.h b/include/CompilerKit/Ref.h new file mode 100644 index 0000000..863a100 --- /dev/null +++ b/include/CompilerKit/Ref.h @@ -0,0 +1,77 @@ + +/* + * ======================================================== + * + * CompilerKit + * Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. + * + * ======================================================== + */ + +#pragma once + +#include <CompilerKit/Detail/Config.h> + +namespace CompilerKit { +/// @author Amlal El Mahrouss +/// @brief Reference holder class, refers to a pointer of data in static memory. +template <typename T> +class Ref final { + public: + explicit Ref() = default; + + ~Ref() { + if (m_Strong) { + MUST_PASS(m_Class); + if (m_Class) delete m_Class; + m_Class = nullptr; + } + } + + NECTI_COPY_DEFAULT(Ref); + + public: + explicit Ref(T* cls, const bool& strong = false) : m_Class(cls), m_Strong(strong) {} + + Ref& operator=(T ref) { + *m_Class = ref; + return *this; + } + + public: + T* operator->() const { return m_Class; } + + T& Leak() { return *m_Class; } + + T operator*() { return *m_Class; } + + bool IsStrong() const { return m_Strong; } + + explicit operator bool() { return *m_Class; } + + private: + T* m_Class{nullptr}; + bool m_Strong{false}; +}; + +// @author Amlal El Mahrouss +// @brief Non null Reference holder class, refers to a pointer of data in static memory. +template <typename T> +class NonNullRef final { + public: + explicit NonNullRef() = delete; + + explicit NonNullRef(T* ref) : m_Ref(ref, true) {} + + Ref<T>& operator->() { + MUST_PASS(m_Ref); + return m_Ref; + } + + NonNullRef& operator=(const NonNullRef<T>& ref) = delete; + NonNullRef(const NonNullRef<T>& ref) = default; + + private: + Ref<T> m_Ref{nullptr}; +}; +} // namespace CompilerKit diff --git a/include/CompilerKit/UUID.h b/include/CompilerKit/UUID.h new file mode 100644 index 0000000..2993b8b --- /dev/null +++ b/include/CompilerKit/UUID.h @@ -0,0 +1,826 @@ +#ifndef STDUUID_H +#define STDUUID_H + +#include <array> +#include <atomic> +#include <cctype> +#include <chrono> +#include <cstring> +#include <functional> +#include <iomanip> +#include <iterator> +#include <memory> +#include <numeric> +#include <optional> +#include <random> +#include <sstream> +#include <string> +#include <string_view> +#include <type_traits> + +#ifdef __cplusplus + +#if (__cplusplus >= 202002L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) +#define LIBUUID_CPP20_OR_GREATER +#endif + +#endif + +#ifdef LIBUUID_CPP20_OR_GREATER +#include <span> +#else +#include <gsl/span> +#endif + +#ifdef _WIN32 + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#ifdef UUID_SYSTEM_GENERATOR +#include <objbase.h> +#endif + +#ifdef UUID_TIME_GENERATOR +#include <iphlpapi.h> +#pragma comment(lib, "IPHLPAPI.lib") +#endif + +#elif defined(__linux__) || defined(__unix__) + +#ifdef UUID_SYSTEM_GENERATOR +#include <uuid/uuid.h> +#endif + +#elif defined(__APPLE__) + +#ifdef UUID_SYSTEM_GENERATOR +#include <CoreFoundation/CFUUID.h> +#endif + +#endif + +namespace uuids { +#ifdef __cpp_lib_span +template <class ElementType, std::size_t Extent> +using span = std::span<ElementType, Extent>; +#else +template <class ElementType, std::ptrdiff_t Extent> +using span = gsl::span<ElementType, Extent>; +#endif + +namespace Detail { + template <typename TChar> + [[nodiscard]] constexpr inline unsigned char hex2char(TChar const ch) noexcept { + if (ch >= static_cast<TChar>('0') && ch <= static_cast<TChar>('9')) + return static_cast<unsigned char>(ch - static_cast<TChar>('0')); + if (ch >= static_cast<TChar>('a') && ch <= static_cast<TChar>('f')) + return static_cast<unsigned char>(10 + ch - static_cast<TChar>('a')); + if (ch >= static_cast<TChar>('A') && ch <= static_cast<TChar>('F')) + return static_cast<unsigned char>(10 + ch - static_cast<TChar>('A')); + return 0; + } + + template <typename TChar> + [[nodiscard]] constexpr std::basic_string_view<TChar> to_string_view(TChar const* str) noexcept { + return str; + } + + template <typename StringType> + [[nodiscard]] constexpr std::basic_string_view<typename StringType::value_type, + typename StringType::traits_type> + to_string_view(StringType const& str) noexcept { + return str; + } + + class sha1 { + public: + using digest32_t = uint32_t[5]; + using digest8_t = uint8_t[20]; + + static constexpr unsigned int block_bytes = 64; + + [[nodiscard]] inline static uint32_t left_rotate(uint32_t value, size_t const count) noexcept { + return (value << count) ^ (value >> (32 - count)); + } + + sha1() { reset(); } + + void reset() noexcept { + m_digest[0] = 0x67452301; + m_digest[1] = 0xEFCDAB89; + m_digest[2] = 0x98BADCFE; + m_digest[3] = 0x10325476; + m_digest[4] = 0xC3D2E1F0; + m_blockByteIndex = 0; + m_byteCount = 0; + } + + void process_byte(uint8_t octet) { + this->m_block[this->m_blockByteIndex++] = octet; + ++this->m_byteCount; + if (m_blockByteIndex == block_bytes) { + this->m_blockByteIndex = 0; + process_block(); + } + } + + void process_block(void const* const start, void const* const end) { + const uint8_t* begin = static_cast<const uint8_t*>(start); + const uint8_t* finish = static_cast<const uint8_t*>(end); + while (begin != finish) { + process_byte(*begin); + begin++; + } + } + + void process_bytes(void const* const data, size_t const len) { + const uint8_t* block = static_cast<const uint8_t*>(data); + process_block(block, block + len); + } + + uint32_t const* get_digest(digest32_t digest) { + size_t const bitCount = this->m_byteCount * 8; + process_byte(0x80); + if (this->m_blockByteIndex > 56) { + while (m_blockByteIndex != 0) { + process_byte(0); + } + while (m_blockByteIndex < 56) { + process_byte(0); + } + } else { + while (m_blockByteIndex < 56) { + process_byte(0); + } + } + process_byte(0); + process_byte(0); + process_byte(0); + process_byte(0); + process_byte(static_cast<unsigned char>((bitCount >> 24) & 0xFF)); + process_byte(static_cast<unsigned char>((bitCount >> 16) & 0xFF)); + process_byte(static_cast<unsigned char>((bitCount >> 8) & 0xFF)); + process_byte(static_cast<unsigned char>((bitCount) & 0xFF)); + + memcpy(digest, m_digest, 5 * sizeof(uint32_t)); + return digest; + } + + uint8_t const* get_digest_bytes(digest8_t digest) { + digest32_t d32; + get_digest(d32); + size_t di = 0; + digest[di++] = static_cast<uint8_t>(d32[0] >> 24); + digest[di++] = static_cast<uint8_t>(d32[0] >> 16); + digest[di++] = static_cast<uint8_t>(d32[0] >> 8); + digest[di++] = static_cast<uint8_t>(d32[0] >> 0); + + digest[di++] = static_cast<uint8_t>(d32[1] >> 24); + digest[di++] = static_cast<uint8_t>(d32[1] >> 16); + digest[di++] = static_cast<uint8_t>(d32[1] >> 8); + digest[di++] = static_cast<uint8_t>(d32[1] >> 0); + + digest[di++] = static_cast<uint8_t>(d32[2] >> 24); + digest[di++] = static_cast<uint8_t>(d32[2] >> 16); + digest[di++] = static_cast<uint8_t>(d32[2] >> 8); + digest[di++] = static_cast<uint8_t>(d32[2] >> 0); + + digest[di++] = static_cast<uint8_t>(d32[3] >> 24); + digest[di++] = static_cast<uint8_t>(d32[3] >> 16); + digest[di++] = static_cast<uint8_t>(d32[3] >> 8); + digest[di++] = static_cast<uint8_t>(d32[3] >> 0); + + digest[di++] = static_cast<uint8_t>(d32[4] >> 24); + digest[di++] = static_cast<uint8_t>(d32[4] >> 16); + digest[di++] = static_cast<uint8_t>(d32[4] >> 8); + digest[di++] = static_cast<uint8_t>(d32[4] >> 0); + + return digest; + } + + private: + void process_block() { + uint32_t w[80]; + for (size_t i = 0; i < 16; i++) { + w[i] = static_cast<uint32_t>(m_block[i * 4 + 0] << 24); + w[i] |= static_cast<uint32_t>(m_block[i * 4 + 1] << 16); + w[i] |= static_cast<uint32_t>(m_block[i * 4 + 2] << 8); + w[i] |= static_cast<uint32_t>(m_block[i * 4 + 3]); + } + for (size_t i = 16; i < 80; i++) { + w[i] = left_rotate((w[i - 3] ^ w[i - 8] ^ w[i - 14] ^ w[i - 16]), 1); + } + + uint32_t a = m_digest[0]; + uint32_t b = m_digest[1]; + uint32_t c = m_digest[2]; + uint32_t d = m_digest[3]; + uint32_t e = m_digest[4]; + + for (std::size_t i = 0; i < 80; ++i) { + uint32_t f = 0; + uint32_t k = 0; + + if (i < 20) { + f = (b & c) | (~b & d); + k = 0x5A827999; + } else if (i < 40) { + f = b ^ c ^ d; + k = 0x6ED9EBA1; + } else if (i < 60) { + f = (b & c) | (b & d) | (c & d); + k = 0x8F1BBCDC; + } else { + f = b ^ c ^ d; + k = 0xCA62C1D6; + } + uint32_t temp = left_rotate(a, 5) + f + e + k + w[i]; + e = d; + d = c; + c = left_rotate(b, 30); + b = a; + a = temp; + } + + m_digest[0] += a; + m_digest[1] += b; + m_digest[2] += c; + m_digest[3] += d; + m_digest[4] += e; + } + + private: + digest32_t m_digest; + uint8_t m_block[64]; + size_t m_blockByteIndex; + size_t m_byteCount; + }; + + template <typename CharT> + inline constexpr CharT empty_guid[37] = "00000000-0000-0000-0000-000000000000"; + + template <> + inline constexpr wchar_t empty_guid<wchar_t>[37] = L"00000000-0000-0000-0000-000000000000"; + + template <typename CharT> + inline constexpr CharT guid_encoder[17] = "0123456789abcdef"; + + template <> + inline constexpr wchar_t guid_encoder<wchar_t>[17] = L"0123456789abcdef"; +} // namespace Detail + +// -------------------------------------------------------------------------------------------------------------------------- +// UUID format https://tools.ietf.org/html/rfc4122 +// -------------------------------------------------------------------------------------------------------------------------- + +// -------------------------------------------------------------------------------------------------------------------------- +// Field NDR Data Type Octet # Note +// -------------------------------------------------------------------------------------------------------------------------- +// time_low unsigned long 0 - 3 The low field +// of the timestamp. time_mid unsigned short 4 - 5 +// The middle field of the timestamp. time_hi_and_version unsigned +// short 6 - 7 The high field of the timestamp multiplexed +// with the version number. clock_seq_hi_and_reserved unsigned small 8 +// The high field of the clock sequence multiplexed with the variant. +// clock_seq_low unsigned small 9 The low +// field of the clock sequence. node character 10 +// - 15 The spatially unique node identifier. +// -------------------------------------------------------------------------------------------------------------------------- +// 0 1 2 3 +// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | time_low | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | time_mid | time_hi_and_version | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// |clk_seq_hi_res | clk_seq_low | node (0-1) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +// | node (2-5) | +// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +// -------------------------------------------------------------------------------------------------------------------------- +// enumerations +// -------------------------------------------------------------------------------------------------------------------------- + +// indicated by a bit pattern in octet 8, marked with N in +// xxxxxxxx-xxxx-xxxx-Nxxx-xxxxxxxxxxxx +enum class uuid_variant { + // NCS backward compatibility (with the obsolete Apollo Network Computing + // System 1.5 UUID format) N bit pattern: 0xxx > the first 6 octets of the + // UUID are a 48-bit timestamp (the number of 4 microsecond units of time + // since 1 Jan 1980 UTC); > the next 2 octets are reserved; > the next octet + // is the "address family"; > the final 7 octets are a 56-bit host ID in the + // form specified by the address family + ncs, + + // RFC 4122/DCE 1.1 + // N bit pattern: 10xx + // > big-endian byte order + rfc, + + // Microsoft Corporation backward compatibility + // N bit pattern: 110x + // > little endian byte order + // > formely used in the Component Object Model (COM) library + microsoft, + + // reserved for possible future definition + // N bit pattern: 111x + reserved +}; + +// indicated by a bit pattern in octet 6, marked with M in +// xxxxxxxx-xxxx-Mxxx-xxxx-xxxxxxxxxxxx +enum class uuid_version { + none = 0, // only possible for nil or invalid uuids + time_based = 1, // The time-based version specified in RFC 4122 + dce_security = 2, // DCE Security version, with embedded POSIX UIDs. + name_based_md5 = 3, // The name-based version specified in RFS 4122 with MD5 hashing + random_number_based = 4, // The randomly or pseudo-randomly generated version + // specified in RFS 4122 + name_based_sha1 = 5 // The name-based version specified in RFS 4122 with SHA1 hashing +}; + +// Forward declare uuid & to_string so that we can declare to_string as a friend +// later. +class uuid; +template <class CharT = char, class Traits = std::char_traits<CharT>, + class Allocator = std::allocator<CharT>> +std::basic_string<CharT, Traits, Allocator> to_string(uuid const& id); + +// -------------------------------------------------------------------------------------------------------------------------- +// uuid class +// -------------------------------------------------------------------------------------------------------------------------- +class uuid { + public: + using value_type = uint8_t; + + constexpr uuid() noexcept = default; + + uuid(value_type (&arr)[16]) noexcept { + std::copy(std::cbegin(arr), std::cend(arr), std::begin(data)); + } + + constexpr uuid(std::array<value_type, 16> const& arr) noexcept : data{arr} {} + + explicit uuid(span<value_type, 16> bytes) { + std::copy(std::cbegin(bytes), std::cend(bytes), std::begin(data)); + } + + template <typename ForwardIterator> + explicit uuid(ForwardIterator first, ForwardIterator last) { + if (std::distance(first, last) == 16) std::copy(first, last, std::begin(data)); + } + + [[nodiscard]] constexpr uuid_variant variant() const noexcept { + if ((data[8] & 0x80) == 0x00) + return uuid_variant::ncs; + else if ((data[8] & 0xC0) == 0x80) + return uuid_variant::rfc; + else if ((data[8] & 0xE0) == 0xC0) + return uuid_variant::microsoft; + else + return uuid_variant::reserved; + } + + [[nodiscard]] constexpr uuid_version version() const noexcept { + if ((data[6] & 0xF0) == 0x10) + return uuid_version::time_based; + else if ((data[6] & 0xF0) == 0x20) + return uuid_version::dce_security; + else if ((data[6] & 0xF0) == 0x30) + return uuid_version::name_based_md5; + else if ((data[6] & 0xF0) == 0x40) + return uuid_version::random_number_based; + else if ((data[6] & 0xF0) == 0x50) + return uuid_version::name_based_sha1; + else + return uuid_version::none; + } + + [[nodiscard]] constexpr bool is_nil() const noexcept { + for (size_t i = 0; i < data.size(); ++i) + if (data[i] != 0) return false; + return true; + } + + void swap(uuid& other) noexcept { data.swap(other.data); } + + [[nodiscard]] inline span<std::byte const, 16> as_bytes() const { + return span<std::byte const, 16>(reinterpret_cast<std::byte const*>(data.data()), 16); + } + + template <typename StringType> + [[nodiscard]] constexpr static bool is_valid_uuid(StringType const& in_str) noexcept { + auto str = Detail::to_string_view(in_str); + bool firstDigit = true; + size_t hasBraces = 0; + size_t index = 0; + + if (str.empty()) return false; + + if (str.front() == '{') hasBraces = 1; + if (hasBraces && str.back() != '}') return false; + + for (size_t i = hasBraces; i < str.size() - hasBraces; ++i) { + if (str[i] == '-') continue; + + if (index >= 16 || !std::isxdigit(static_cast<unsigned char>(str[i]))) { + return false; + } + + if (firstDigit) { + firstDigit = false; + } else { + index++; + firstDigit = true; + } + } + + if (index < 16) { + return false; + } + + return true; + } + + template <typename StringType> + [[nodiscard]] constexpr static std::optional<uuid> from_string( + StringType const& in_str) noexcept { + auto str = Detail::to_string_view(in_str); + bool firstDigit = true; + size_t hasBraces = 0; + size_t index = 0; + + std::array<uint8_t, 16> data{{0}}; + + if (str.empty()) return {}; + + if (str.front() == '{') hasBraces = 1; + if (hasBraces && str.back() != '}') return {}; + + for (size_t i = hasBraces; i < str.size() - hasBraces; ++i) { + if (str[i] == '-') continue; + + if (index >= 16 || !std::isxdigit(static_cast<unsigned char>(str[i]))) { + return {}; + } + + if (firstDigit) { + data[index] = static_cast<uint8_t>(Detail::hex2char(str[i]) << 4); + firstDigit = false; + } else { + data[index] = static_cast<uint8_t>(data[index] | Detail::hex2char(str[i])); + index++; + firstDigit = true; + } + } + + if (index < 16) { + return {}; + } + + return uuid{data}; + } + + private: + std::array<value_type, 16> data{{0}}; + + friend bool operator==(uuid const& lhs, uuid const& rhs) noexcept; + friend bool operator<(uuid const& lhs, uuid const& rhs) noexcept; + + template <class Elem, class Traits> + friend std::basic_ostream<Elem, Traits>& operator<<(std::basic_ostream<Elem, Traits>& s, + uuid const& id); + + template <class CharT, class Traits, class Allocator> + friend std::basic_string<CharT, Traits, Allocator> to_string(uuid const& id); + + friend std::hash<uuid>; +}; + +// -------------------------------------------------------------------------------------------------------------------------- +// operators and non-member functions +// -------------------------------------------------------------------------------------------------------------------------- + +[[nodiscard]] inline bool operator==(uuid const& lhs, uuid const& rhs) noexcept { + return lhs.data == rhs.data; +} + +[[nodiscard]] inline bool operator!=(uuid const& lhs, uuid const& rhs) noexcept { + return !(lhs == rhs); +} + +[[nodiscard]] inline bool operator<(uuid const& lhs, uuid const& rhs) noexcept { + return lhs.data < rhs.data; +} + +template <class CharT, class Traits, class Allocator> +[[nodiscard]] inline std::basic_string<CharT, Traits, Allocator> to_string(uuid const& id) { + std::basic_string<CharT, Traits, Allocator> uustr{Detail::empty_guid<CharT>}; + + for (size_t i = 0, index = 0; i < 36; ++i) { + if (i == 8 || i == 13 || i == 18 || i == 23) { + continue; + } + uustr[i] = Detail::guid_encoder<CharT>[id.data[index] >> 4 & 0x0f]; + uustr[++i] = Detail::guid_encoder<CharT>[id.data[index] & 0x0f]; + index++; + } + + return uustr; +} + +template <class Elem, class Traits> +std::basic_ostream<Elem, Traits>& operator<<(std::basic_ostream<Elem, Traits>& s, uuid const& id) { + s << to_string(id); + return s; +} + +inline void swap(uuids::uuid& lhs, uuids::uuid& rhs) noexcept { + lhs.swap(rhs); +} + +// -------------------------------------------------------------------------------------------------------------------------- +// namespace IDs that could be used for generating name-based uuids +// -------------------------------------------------------------------------------------------------------------------------- + +// Name string is a fully-qualified domain name +static uuid uuid_namespace_dns{{0x6b, 0xa7, 0xb8, 0x10, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, + 0xc0, 0x4f, 0xd4, 0x30, 0xc8}}; + +// Name string is a URL +static uuid uuid_namespace_url{{0x6b, 0xa7, 0xb8, 0x11, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, + 0xc0, 0x4f, 0xd4, 0x30, 0xc8}}; + +// Name string is an ISO OID (See https://oidref.com/, +// https://en.wikipedia.org/wiki/Object_identifier) +static uuid uuid_namespace_oid{{0x6b, 0xa7, 0xb8, 0x12, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, + 0xc0, 0x4f, 0xd4, 0x30, 0xc8}}; + +// Name string is an X.500 DN, in DER or a text output format (See +// https://en.wikipedia.org/wiki/X.500, +// https://en.wikipedia.org/wiki/Abstract_Syntax_Notation_One) +static uuid uuid_namespace_x500{{0x6b, 0xa7, 0xb8, 0x14, 0x9d, 0xad, 0x11, 0xd1, 0x80, 0xb4, 0x00, + 0xc0, 0x4f, 0xd4, 0x30, 0xc8}}; + +// -------------------------------------------------------------------------------------------------------------------------- +// uuid generators +// -------------------------------------------------------------------------------------------------------------------------- + +#ifdef UUID_SYSTEM_GENERATOR +class uuid_system_generator { + public: + using result_type = uuid; + + uuid operator()() { +#ifdef _WIN32 + GUID newId{}; /// AMLALE: Should be zero-initialized. + HRESULT hr = ::CoCreateGuid(&newId); + + if (FAILED(hr)) { + throw std::system_error(hr, std::system_category(), "CoCreateGuid failed"); + } + + std::array<uint8_t, 16> bytes = {{static_cast<unsigned char>((newId.Data1 >> 24) & 0xFF), + static_cast<unsigned char>((newId.Data1 >> 16) & 0xFF), + static_cast<unsigned char>((newId.Data1 >> 8) & 0xFF), + static_cast<unsigned char>((newId.Data1) & 0xFF), + static_cast<unsigned char>((newId.Data2 >> 8) & 0xFF), + static_cast<unsigned char>((newId.Data2) & 0xFF), + static_cast<unsigned char>((newId.Data3 >> 8) & 0xFF), + static_cast<unsigned char>((newId.Data3) & 0xFF), + newId.Data4[0], newId.Data4[1], newId.Data4[2], + newId.Data4[3], newId.Data4[4], newId.Data4[5], + newId.Data4[6], newId.Data4[7]}}; + + return uuid{std::begin(bytes), std::end(bytes)}; + +#elif defined(__linux__) || defined(__unix__) + + uuid_t id; + uuid_generate(id); + + std::array<uint8_t, 16> bytes = {{id[0], id[1], id[2], id[3], id[4], id[5], id[6], id[7], id[8], + id[9], id[10], id[11], id[12], id[13], id[14], id[15]}}; + + return uuid{std::begin(bytes), std::end(bytes)}; + +#elif defined(__APPLE__) + auto newId = CFUUIDCreate(NULL); + auto bytes = CFUUIDGetUUIDBytes(newId); + CFRelease(newId); + + std::array<uint8_t, 16> arrbytes = {{bytes.byte0, bytes.byte1, bytes.byte2, bytes.byte3, + bytes.byte4, bytes.byte5, bytes.byte6, bytes.byte7, + bytes.byte8, bytes.byte9, bytes.byte10, bytes.byte11, + bytes.byte12, bytes.byte13, bytes.byte14, bytes.byte15}}; + return uuid{std::begin(arrbytes), std::end(arrbytes)}; +#else + return uuid{}; +#endif + } +}; +#endif + +template <typename UniformRandomNumberGenerator> +class basic_uuid_random_generator { + public: + using engine_type = UniformRandomNumberGenerator; + + explicit basic_uuid_random_generator(engine_type& gen) : generator(&gen, [](auto) {}) {} + explicit basic_uuid_random_generator(engine_type* gen) : generator(gen, [](auto) {}) {} + + [[nodiscard]] uuid operator()() { + alignas(uint32_t) uint8_t bytes[16]; + for (int i = 0; i < 16; i += 4) + *reinterpret_cast<uint32_t*>(bytes + i) = distribution(*generator); + + // variant must be 10xxxxxx + bytes[8] &= 0xBF; + bytes[8] |= 0x80; + + // version must be 0100xxxx + bytes[6] &= 0x4F; + bytes[6] |= 0x40; + + return uuid{std::begin(bytes), std::end(bytes)}; + } + + private: + std::uniform_int_distribution<uint32_t> distribution; + std::shared_ptr<UniformRandomNumberGenerator> generator; +}; + +using uuid_random_generator = basic_uuid_random_generator<std::mt19937>; + +class uuid_name_generator { + public: + explicit uuid_name_generator(uuid const& namespace_uuid) noexcept : nsuuid(namespace_uuid) {} + + template <typename StringType> + [[nodiscard]] uuid operator()(StringType const& name) { + reset(); + process_characters(Detail::to_string_view(name)); + return make_uuid(); + } + + private: + void reset() { + hasher.reset(); + std::byte bytes[16]; + auto nsbytes = nsuuid.as_bytes(); + std::copy(std::cbegin(nsbytes), std::cend(nsbytes), bytes); + hasher.process_bytes(bytes, 16); + } + + template <typename CharT, typename Traits> + void process_characters(std::basic_string_view<CharT, Traits> const str) { + for (uint32_t c : str) { + hasher.process_byte(static_cast<uint8_t>(c & 0xFF)); + if constexpr (!std::is_same_v<CharT, char>) { + hasher.process_byte(static_cast<uint8_t>((c >> 8) & 0xFF)); + hasher.process_byte(static_cast<uint8_t>((c >> 16) & 0xFF)); + hasher.process_byte(static_cast<uint8_t>((c >> 24) & 0xFF)); + } + } + } + + [[nodiscard]] uuid make_uuid() { + Detail::sha1::digest8_t digest; + hasher.get_digest_bytes(digest); + + // variant must be 0b10xxxxxx + digest[8] &= 0xBF; + digest[8] |= 0x80; + + // version must be 0b0101xxxx + digest[6] &= 0x5F; + digest[6] |= 0x50; + + return uuid{digest, digest + 16}; + } + + private: + uuid nsuuid; + Detail::sha1 hasher; +}; + +#ifdef UUID_TIME_GENERATOR +// !!! DO NOT USE THIS IN PRODUCTION +// this implementation is unreliable for good uuids +class uuid_time_generator { + using mac_address = std::array<unsigned char, 6>; + + std::optional<mac_address> device_address; + + [[nodiscard]] bool get_mac_address() { + if (device_address.has_value()) { + return true; + } + +#ifdef _WIN32 + DWORD len = 0; + auto ret = GetAdaptersInfo(nullptr, &len); + if (ret != ERROR_BUFFER_OVERFLOW) return false; + std::vector<unsigned char> buf(len); + auto pips = reinterpret_cast<PIP_ADAPTER_INFO>(&buf.front()); + ret = GetAdaptersInfo(pips, &len); + if (ret != ERROR_SUCCESS) return false; + mac_address addr; + std::copy(pips->Address, pips->Address + 6, std::begin(addr)); + device_address = addr; +#endif + + return device_address.has_value(); + } + + [[nodiscard]] long long get_time_intervals() { + auto start = std::chrono::system_clock::from_time_t(time_t(-12219292800)); + auto diff = std::chrono::system_clock::now() - start; + auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(diff).count(); + return ns / 100; + } + + [[nodiscard]] static unsigned short get_clock_sequence() { + static std::mt19937 clock_gen(std::random_device{}()); + static std::uniform_int_distribution<unsigned short> clock_dis; + static std::atomic_ushort clock_sequence = clock_dis(clock_gen); + return clock_sequence++; + } + + public: + [[nodiscard]] uuid operator()() { + if (get_mac_address()) { + std::array<uuids::uuid::value_type, 16> data; + + auto tm = get_time_intervals(); + + auto clock_seq = get_clock_sequence(); + + auto ptm = reinterpret_cast<uuids::uuid::value_type*>(&tm); + + memcpy(&data[0], ptm + 4, 4); + memcpy(&data[4], ptm + 2, 2); + memcpy(&data[6], ptm, 2); + + memcpy(&data[8], &clock_seq, 2); + + // variant must be 0b10xxxxxx + data[8] &= 0xBF; + data[8] |= 0x80; + + // version must be 0b0001xxxx + data[6] &= 0x1F; + data[6] |= 0x10; + + memcpy(&data[10], &device_address.value()[0], 6); + + return uuids::uuid{std::cbegin(data), std::cend(data)}; + } + + return {}; + } +}; +#endif +} // namespace uuids + +namespace std { +template <> +struct hash<uuids::uuid> { + using argument_type = uuids::uuid; + using result_type = std::size_t; + + [[nodiscard]] result_type operator()(argument_type const& uuid) const { +#ifdef UUID_HASH_STRING_BASED + std::hash<std::string> hasher; + return static_cast<result_type>(hasher(uuids::to_string(uuid))); +#else + uint64_t l = + static_cast<uint64_t>(uuid.data[0]) << 56 | static_cast<uint64_t>(uuid.data[1]) << 48 | + static_cast<uint64_t>(uuid.data[2]) << 40 | static_cast<uint64_t>(uuid.data[3]) << 32 | + static_cast<uint64_t>(uuid.data[4]) << 24 | static_cast<uint64_t>(uuid.data[5]) << 16 | + static_cast<uint64_t>(uuid.data[6]) << 8 | static_cast<uint64_t>(uuid.data[7]); + uint64_t h = + static_cast<uint64_t>(uuid.data[8]) << 56 | static_cast<uint64_t>(uuid.data[9]) << 48 | + static_cast<uint64_t>(uuid.data[10]) << 40 | static_cast<uint64_t>(uuid.data[11]) << 32 | + static_cast<uint64_t>(uuid.data[12]) << 24 | static_cast<uint64_t>(uuid.data[13]) << 16 | + static_cast<uint64_t>(uuid.data[14]) << 8 | static_cast<uint64_t>(uuid.data[15]); + + if constexpr (sizeof(result_type) > 4) { + return result_type(l ^ h); + } else { + uint64_t hash64 = l ^ h; + return result_type(uint32_t(hash64 >> 32) ^ uint32_t(hash64)); + } +#endif + } +}; +} // namespace std + +#endif /* STDUUID_H */ diff --git a/include/CompilerKit/Utilities/Assembler.h b/include/CompilerKit/Utilities/Assembler.h new file mode 100644 index 0000000..fc965f0 --- /dev/null +++ b/include/CompilerKit/Utilities/Assembler.h @@ -0,0 +1,92 @@ +/* ======================================== + + Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license + +======================================== */ + +#pragma once + +#include <CompilerKit/AST.h> +#include <CompilerKit/CodeGenerator.h> +#include <CompilerKit/Utilities/Compiler.h> + +using namespace CompilerKit; + +/// @brief Get Number from lineBuffer. +/// @param lineBuffer the lineBuffer to fetch from. +/// @param numberKey where to seek that number. +/// @return A numbercast of 32-bit width. +static NumberCast32 GetNumber32(STLString lineBuffer, STLString numberKey) { + auto pos = lineBuffer.find(numberKey) + numberKey.size(); + + while (lineBuffer[pos] == ' ') { + ++pos; + } + + switch (lineBuffer[pos + 1]) { + case 'x': { + if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 16); !res) { + if (errno != 0) { + CompilerKit::Detail::print_error("invalid hex number: " + lineBuffer, "CompilerKit"); + throw std::runtime_error("invalid_hex"); + } + } + + NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 16)); + + if (kVerbose) { + kStdOut << "asm: found a base 16 number here: " << lineBuffer.substr(pos) << "\n"; + } + + return numOffset; + } + case 'b': { + if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 2); !res) { + if (errno != 0) { + CompilerKit::Detail::print_error("invalid binary number:" + lineBuffer, "CompilerKit"); + throw std::runtime_error("invalid_bin"); + } + } + + NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 2)); + + if (kVerbose) { + kStdOut << "asm: found a base 2 number here:" << lineBuffer.substr(pos) << "\n"; + } + + return numOffset; + } + case 'o': { + if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 7); !res) { + if (errno != 0) { + CompilerKit::Detail::print_error("invalid octal number: " + lineBuffer, "CompilerKit"); + throw std::runtime_error("invalid_octal"); + } + } + + NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 7)); + + if (kVerbose) { + kStdOut << "asm: found a base 8 number here:" << lineBuffer.substr(pos) << "\n"; + } + + return numOffset; + } + default: { + if (auto res = strtol(lineBuffer.substr(pos).c_str(), nullptr, 10); !res) { + if (errno != 0) { + CompilerKit::Detail::print_error("invalid hex number: " + lineBuffer, "CompilerKit"); + throw std::runtime_error("invalid_hex"); + } + } + + NumberCast32 numOffset(strtol(lineBuffer.substr(pos).c_str(), nullptr, 10)); + + if (kVerbose) { + kStdOut << "asm: found a base 10 number here:" << lineBuffer.substr(pos) << "\n"; + } + + return numOffset; + } + } +} diff --git a/include/CompilerKit/Utilities/Compiler.h b/include/CompilerKit/Utilities/Compiler.h new file mode 100644 index 0000000..bbca020 --- /dev/null +++ b/include/CompilerKit/Utilities/Compiler.h @@ -0,0 +1,123 @@ +/* ======================================== + + Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license + +======================================== */ + +#pragma once + +#include <CompilerKit/AST.h> +#include <CompilerKit/CodeGenerator.h> +#include <CompilerKit/Detail/Config.h> +#include <CompilerKit/ErrorID.h> +#include <ThirdParty/Dialogs/Dialogs.h> +#include <iostream> + +#define kZero64Section ".zero64" +#define kCode64Section ".code64" +#define kData64Section ".data64" + +#define kZero128Section ".zero128" +#define kCode128Section ".code128" +#define kData128Section ".data128" + +#define kBlank "\e[0;30m" +#define kRed "\e[0;31m" +#define kWhite "\e[0;97m" +#define kYellow "\e[0;33m" + +#define kStdOut (std::cout << kRed << "drv: " << kWhite) +#define kStdErr (std::cerr << kYellow << "drv: " << kWhite) + +#define kPrintF kStdOut +#define kPrintErr kStdErr + +inline static UInt32 kErrorLimit = 10; +inline static UInt32 kAcceptableErrors = 0; +inline static bool kVerbose = false; +inline static bool kOutputAsBinary = false; + +namespace CompilerKit::Detail { +/// @brief Blob structure +struct Blob final { + std::vector<Char> mBlob{}; // PEF code/bss/data blob. + UIntPtr mOffset{0UL}; // the offset of the PEF container header... + + explicit operator bool() { + return mBlob.empty() && mOffset > 0UL; + } +}; + +inline void print_error(STLString reason, STLString file) noexcept { + if (reason[0] == '\n') reason.erase(0, 1); + + kStdErr << reason << kBlank << std::endl; + + if (kAcceptableErrors > kErrorLimit) std::exit(NECTI_EXEC_ERROR); + + ++kAcceptableErrors; +} + +inline void print_warning(STLString reason, STLString file) noexcept { + if (reason[0] == '\n') reason.erase(0, 1); + + kStdOut << kYellow << reason << kBlank << std::endl; +} + +/// @internal +/// @brief Handler for SIGSEGV signal. +inline void drvi_crash_handler(std::int32_t id) { + CompilerKit::STLString verbose_header = "LIBCOMPILER CRASH REPORT - "; + verbose_header += kDistVersion; + verbose_header += " - "; + verbose_header += CompilerKit::current_date(); + + for (auto& ch : verbose_header) { + std::cout << '='; + } + + std::cout << std::endl; + + std::cout << verbose_header << std::endl; + + for (auto& ch : verbose_header) { + std::cout << '='; + } + + std::cout << std::endl; + + kStdOut << "DATE: " << CompilerKit::current_date() << std::endl; + kStdOut << "VERSION: " << kDistVersion << std::endl; + kStdOut << "ERRNO: " << errno << std::endl; + kStdOut << "ERRNO(STRING): " << strerror(errno) << std::endl; + + switch (id) { + case SIGSEGV: { + kStdOut << "SIGNAL: Segmentation Fault." << kBlank << std::endl; + break; + } + case SIGABRT: { + kStdOut << "SIGNAL: Aborted." << kBlank << std::endl; + break; + } + } + + std::cout << kWhite; + + for (auto& ch : verbose_header) { + std::cout << '='; + } + + std::cout << std::endl; + + std::cout << verbose_header << std::endl; + + for (auto& ch : verbose_header) { + std::cout << '='; + } + + std::cout << std::endl; + + std::exit(NECTI_EXEC_ERROR); +} +} // namespace Detail diff --git a/include/CompilerKit/Utilities/DLL.h b/include/CompilerKit/Utilities/DLL.h new file mode 100644 index 0000000..5bfe032 --- /dev/null +++ b/include/CompilerKit/Utilities/DLL.h @@ -0,0 +1,67 @@ +/* ======================================== + + Copyright (C) 2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license + +======================================== */ + +#pragma once + +#include <CompilerKit/Detail/Config.h> +#include <dlfcn.h> +#include <mutex> + +struct CompilerKitDylibTraits; + +typedef Int32 (*CompilerKitEntrypoint)(Int32 argc, Char const* argv[]); +typedef VoidPtr CompilerKitDylib; + +struct CompilerKitDylibTraits final { + CompilerKitDylib fDylib{nullptr}; + CompilerKitEntrypoint fEntrypoint{nullptr}; + std::mutex fMutex; + + explicit operator bool() { + return fDylib && fEntrypoint; + } + + CompilerKitDylibTraits& operator()(const Char* path, const Char* fEntrypoint) { + std::lock_guard<std::mutex> lock(this->fMutex); + + if (!path || !fEntrypoint) return *this; + + if (this->fDylib) { + dlclose(this->fDylib); + this->fDylib = nullptr; + } + + this->fDylib = dlopen(path, RTLD_LAZY); + + if (!this->fDylib) { + return *this; + } + + this->fEntrypoint = (CompilerKitEntrypoint) dlsym(this->fDylib, fEntrypoint); + + if (!this->fEntrypoint) { + dlclose(this->fDylib); + this->fDylib = nullptr; + + return *this; + } + + return *this; + } + + NECTI_COPY_DELETE(CompilerKitDylibTraits); + + CompilerKitDylibTraits() = default; + + ~CompilerKitDylibTraits() { + if (this->fDylib) { + dlclose(this->fDylib); + this->fDylib = nullptr; + } + + this->fEntrypoint = nullptr; + } +}; diff --git a/include/CompilerKit/XCOFF.h b/include/CompilerKit/XCOFF.h new file mode 100644 index 0000000..777f501 --- /dev/null +++ b/include/CompilerKit/XCOFF.h @@ -0,0 +1,43 @@ +/* ======================================== + + Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license + + File: XCOFF.h + Purpose: XCOFF for NeKernel. + + Revision History: + + 04/07/24: Added file (Amlal El Mahrouss) + +======================================== */ + +#ifndef _NECTI_XCOFF_H_ +#define _NECTI_XCOFF_H_ + +#include <CompilerKit/Detail/Config.h> + +#define kXCOFF64Magic 0x01F7 + +#define kXCOFFRelFlg 0x0001 +#define kXCOFFExecutable 0x0002 +#define kXCOFFLnno 0x0004 +#define kXCOFFLSyms 0x0008 + +namespace CompilerKit { +struct XCoffFileHeader; + +/// @brief XCoff file header. +typedef struct XCoffFileHeader { + UInt16 fMagic; + UInt16 fTarget; + UInt16 fNumSecs; + UInt32 fTimeDat; + UIntPtr fSymPtr; + UInt32 fNumSyms; + UInt16 fOptHdr; // ?: Number of bytes in optional header +} XCoffFileHeader; + +typedef struct XCoffFileHeader* XCoffFileHeaderPtr; +} // namespace CompilerKit + +#endif // ifndef _NECTI_XCOFF_H_ diff --git a/include/DebuggerKit/Common.inl b/include/DebuggerKit/Common.inl new file mode 100644 index 0000000..c630041 --- /dev/null +++ b/include/DebuggerKit/Common.inl @@ -0,0 +1,23 @@ +/* ======================================== + + Copyright (C) 2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. + +======================================== */ + +#define kBlank "\e[0;30m" +#define kRed "\e[0;31m" +#define kWhite "\e[0;97m" + +#define kStdOut (std::cout << kRed << "dbg: " << kWhite) + +inline bool kKeepRunning = false; + +#ifdef DK_NEKERNEL_DEBUGGER +inline DebuggerKit::NeKernel::NeKernelContract kKernelDebugger; +#else +inline DebuggerKit::POSIX::POSIXMachContract kUserDebugger; +#endif + +static DebuggerKit::ProcessID kPID = 0L; +static DebuggerKit::CAddress kActiveAddress = nullptr; +static CompilerKit::STLString kPath = ""; diff --git a/include/DebuggerKit/DebuggerContract.h b/include/DebuggerKit/DebuggerContract.h new file mode 100644 index 0000000..e205e26 --- /dev/null +++ b/include/DebuggerKit/DebuggerContract.h @@ -0,0 +1,43 @@ +/* ======================================== + + Copyright (C) 2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. + +======================================== */ + +#pragma once + +#include <DebuggerKit/Detail/Config.h> +#include <unordered_map> + +#define DK_DEBUGGER_CONTRACT : public ::DebuggerKit::IDebuggerContract + +namespace DebuggerKit { +class IDebuggerContract; + +/// =========================================================== /// +/// \brief Debugger contract class in C++, as per the design states. +/// \author Amlal El Mahrouss +/// =========================================================== /// +class IDebuggerContract { + public: + explicit IDebuggerContract() = default; + virtual ~IDebuggerContract() = default; + + public: + IDebuggerContract& operator=(const IDebuggerContract&) = default; + IDebuggerContract(const IDebuggerContract&) = default; + + public: + virtual bool Attach(std::string path, std::string argv, ProcessID& pid) noexcept = 0; + virtual bool BreakAt(std::string symbol) noexcept = 0; + virtual bool Break() noexcept = 0; + virtual bool Continue() noexcept = 0; + virtual bool Detach() noexcept = 0; + + virtual std::unordered_map<uintptr_t, uintptr_t>& Get() { return m_breakpoints; } + + protected: + ProcessID m_pid{(ProcessID) ~0}; + std::unordered_map<uintptr_t, uintptr_t> m_breakpoints; +}; +} // namespace DebuggerKit diff --git a/include/DebuggerKit/Detail/Config.h b/include/DebuggerKit/Detail/Config.h new file mode 100644 index 0000000..0ea3ba1 --- /dev/null +++ b/include/DebuggerKit/Detail/Config.h @@ -0,0 +1,66 @@ +/* ======================================== + + Copyright (C) 2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. + +======================================== */ + +#pragma once + +/// =========================================================== /// +/// @author Amlal El Mahrouss +/// =========================================================== /// + +#include <CompilerKit/Detail/Config.h> + +#include <arpa/inet.h> +#include <sys/socket.h> +#include <sys/types.h> +#include <sys/un.h> + +#include <sys/ptrace.h> +#include <sys/types.h> +#include <sys/user.h> +#include <sys/wait.h> +#include <unistd.h> + +#include <dlfcn.h> + +#ifdef __APPLE__ +#include <mach-o/dyld.h> +#include <mach/mach.h> +#include <mach/mach_error.h> +#endif + +#ifndef kDistRelease + +#define kDistVersion "v0.0.7-debuggerkit" +#define kDistVersionBCD 0x0001 + +#define ToString(X) Stringify(X) +#define Stringify(X) #X + +#define kDistRelease ToString(kDistReleaseBranch) + +#endif // !kDistRelease + +namespace DebuggerKit { +/// =========================================================== /// +/// \brief Process ID +/// =========================================================== /// +typedef uint64_t ProcessID; + +/// =========================================================== /// +/// \brief Address type, a la BSD. +/// =========================================================== /// +typedef char* CAddress; + +namespace Detail { + constexpr auto kDebugCmdLen = 256U; + constexpr auto kDebugPort = 51820; + constexpr auto kDebugMagic = "NE1.0.0;"; + constexpr uint16_t kDebugVersion = 0x0100; + constexpr auto kDebugDelim = ';'; + constexpr auto kDebugEnd = '\r'; + using dk_socket_type = int64_t; +} // namespace Detail +} // namespace DebuggerKit
\ No newline at end of file diff --git a/include/DebuggerKit/NeKernelContract.h b/include/DebuggerKit/NeKernelContract.h new file mode 100644 index 0000000..fe38a22 --- /dev/null +++ b/include/DebuggerKit/NeKernelContract.h @@ -0,0 +1,50 @@ +/* ======================================== + + Copyright (C) 2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. + +======================================== */ + +#ifndef DK_NEKERNEL_CONTRACT_H +#define DK_NEKERNEL_CONTRACT_H + +/// @brief NeKernel Debugging Protocol +/// @author Amlal El Mahrouss + +#ifdef DK_NEKERNEL_DEBUGGER + +#include <CompilerKit/Detail/Config.h> +#include <DebuggerKit/DebuggerContract.h> + +namespace DebuggerKit::NeKernel { +class NeKernelContract; + +/// =========================================================== /// +/// \brief NeKernel Debugger Contract +/// \author Amlal El Mahrouss +/// =========================================================== /// +class NeKernelContract final DK_DEBUGGER_CONTRACT { + public: + NeKernelContract(); + virtual ~NeKernelContract() override; + + public: + NeKernelContract& operator=(const NeKernelContract&) = default; + NeKernelContract(const NeKernelContract&) = default; + + public: + bool Attach(CompilerKit::STLString path, CompilerKit::STLString arg_v, + ProcessID& pid) noexcept override; + bool BreakAt(CompilerKit::STLString symbol) noexcept override; + bool Break() noexcept override; + bool Continue() noexcept override; + bool Detach() noexcept override; + + private: + CompilerKit::STLString m_kernel_path{}; + Detail::dk_socket_type m_socket{0}; +}; +} // namespace DebuggerKit::NeKernel + +#endif // ifdef DK_NEKERNEL_DEBUGGER + +#endif // DK_NEKERNEL_CONTRACT_H diff --git a/include/DebuggerKit/POSIXMachContract.h b/include/DebuggerKit/POSIXMachContract.h new file mode 100644 index 0000000..abf23b5 --- /dev/null +++ b/include/DebuggerKit/POSIXMachContract.h @@ -0,0 +1,155 @@ +/* ======================================== + + Copyright (C) 2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. + +======================================== */ + +#pragma once + +#ifdef DK_MACH_DEBUGGER + +/// @file POSIXMachContract.h +/// @brief POSIX Mach debugger. + +#include <DebuggerKit/DebuggerContract.h> +#include <filesystem> +#include <vector> + +#ifdef __APPLE__ +CK_IMPORT_C kern_return_t mach_vm_write(vm_map_t target_task, mach_vm_address_t address, + vm_offset_t data, mach_msg_type_number_t dataCnt); + +CK_IMPORT_C kern_return_t mach_vm_protect(vm_map_t target_task, mach_vm_address_t address, + mach_vm_size_t size, boolean_t set_maximum, + vm_prot_t new_protection); +#endif + +#define PTRACE_ATTACH PT_ATTACHEXC +#define PTRACE_DETACH PT_DETACH +#define PTRACE_POKETEXT PT_WRITE_I +#define PTRACE_CONT PT_CONTINUE +#define PTRACE_PEEKTEXT PT_READ_I + +namespace DebuggerKit::POSIX { +/// =========================================================== /// +/// \brief POSIXMachContract engine class in C++ +/// \author Amlal El Mahrouss +/// =========================================================== /// +class POSIXMachContract final DK_DEBUGGER_CONTRACT { + public: + explicit POSIXMachContract() = default; + ~POSIXMachContract() override = default; + + public: + POSIXMachContract& operator=(const POSIXMachContract&) = default; + POSIXMachContract(const POSIXMachContract&) = default; + + public: + bool Attach(CompilerKit::STLString path, CompilerKit::STLString argv, + ProcessID& pid) noexcept override { + pid = fork(); + + if (pid == 0) { + if (argv.empty()) { + ptrace(PT_TRACE_ME, 0, nullptr, 0); + kill(getpid(), SIGSTOP); + } + + std::vector<char*> argv_arr; + + argv_arr.push_back(const_cast<char*>(path.c_str())); + argv_arr.push_back(const_cast<char*>(argv.c_str())); + argv_arr.push_back(nullptr); + + execv(path.c_str(), argv_arr.data()); + + _exit(1); + } + + m_path = path; + m_pid = pid; + + pid = this->m_pid; + + return true; + } + + void SetPath(CompilerKit::STLString path) noexcept { + if (path.empty()) { + return; + } + + m_path = path; + } + + bool BreakAt(CompilerKit::STLString symbol) noexcept override { + if (!m_path.empty() && std::filesystem::exists(m_path) && + std::filesystem::is_regular_file(m_path)) { + auto handle = dlopen(m_path.c_str(), RTLD_LAZY); + + if (handle == nullptr) { + return false; + } + + auto addr = dlsym(handle, symbol.c_str()); + + if (addr == nullptr) { + return false; + } + +#ifdef __APPLE__ + task_read_t task; + task_for_pid(mach_task_self(), m_pid, &task); + + uint32_t brk_inst = 0xD43E0000; + + mach_vm_protect(task, (mach_vm_address_t) addr, sizeof(uint32_t), false, + VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE); + + mach_vm_write(task, (mach_vm_address_t) addr, (vm_offset_t) &brk_inst, sizeof(addr)); +#endif + + return true; + } + + return false; + } + +#ifdef __APPLE__ + bool Break() noexcept override { + task_read_t task; + task_for_pid(mach_task_self(), m_pid, &task); + + kern_return_t ret = task_suspend(task); + + return ret == KERN_SUCCESS; + } + + bool Continue() noexcept override { + task_read_t task; + task_for_pid(mach_task_self(), m_pid, &task); + + kern_return_t ret = task_resume(task); + + return ret == KERN_SUCCESS; + } + + bool Detach() noexcept override { + this->Continue(); + + task_read_t task; + task_for_pid(mach_task_self(), m_pid, &task); + + kern_return_t kr = mach_port_deallocate(mach_task_self(), task); + + return kr = KERN_SUCCESS; + } +#endif + + private: + ProcessID m_pid{0}; + CompilerKit::STLString m_path; +}; +} // namespace DebuggerKit::POSIX + +#endif diff --git a/include/LibC++/.gitignore b/include/LibC++/.gitignore new file mode 100644 index 0000000..e3f10ea --- /dev/null +++ b/include/LibC++/.gitignore @@ -0,0 +1 @@ +libc++/ diff --git a/include/LibC++/__abi+unreachable.inl b/include/LibC++/__abi+unreachable.inl new file mode 100644 index 0000000..5628e7d --- /dev/null +++ b/include/LibC++/__abi+unreachable.inl @@ -0,0 +1,16 @@ +/* ======================================== + + Copyright (C) 2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. + +======================================== */ + +#include <LibC++/__abi.h> +#include <LibC++/base_process.h> + +static const int32_t __unreachable_code = 34; + +extern "C" void __compilerkit_unreachable(void) { + std::base_process::signal(__unreachable_code); + + while (1); +}
\ No newline at end of file diff --git a/include/LibC++/__abi.h b/include/LibC++/__abi.h new file mode 100644 index 0000000..206b5ef --- /dev/null +++ b/include/LibC++/__abi.h @@ -0,0 +1,15 @@ +/* ======================================== + + Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. + +======================================== */ + +#pragma once + +#include <LibC++/defines.h> + +__init_decl() + + extern void __compilerkit_unreachable(void); + +__fini_decl()
\ No newline at end of file diff --git a/include/LibC++/__power64.inc b/include/LibC++/__power64.inc new file mode 100644 index 0000000..c06863a --- /dev/null +++ b/include/LibC++/__power64.inc @@ -0,0 +1,39 @@ +# Path: LibC++/__power64.inc +# Language: CompilerKit POWER Assembly support for GNU. +# Build Date: 2024-6-4 + +#ifdef __NECTI__ + +#ifdef __ASSEMBLER__ + +#define lda li +#define sta stw +#define ldw li + +#define r0 0 +#define r1 1 +#define r2 2 +#define r3 3 +#define r4 4 +#define r5 5 +#define r6 6 +#define r7 7 +#define r8 8 +#define r9 9 +#define r10 10 +#define r11 11 +#define r12 12 +#define r13 13 +#define r14 14 +#define r15 15 +#define r16 16 +#define r17 17 +#define r18 18 +#define r19 19 +#define r20 20 + +#define nop mr 0, 0 + +#endif + +#endif diff --git a/include/LibC++/base_alloc.h b/include/LibC++/base_alloc.h new file mode 100644 index 0000000..ea5b5b2 --- /dev/null +++ b/include/LibC++/base_alloc.h @@ -0,0 +1,43 @@ +/* ======================================== + + Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. + +======================================== */ + +#pragma once + +#include <LibC++/defines.h> + +namespace std::base_alloc { +/// @brief allocate a new class. +/// @tparam KindClass the class type to allocate. +template <typename KindClass, typename... Args> +inline KindClass* allocate(Args&&... args) { + return new KindClass(forward(args)...); +} + +/// @brief allocate a new class. +/// @note aborts on error. +/// @tparam KindClass the class type to allocate. +template <typename KindClass, typename... Args> +inline KindClass* allocate_nothrow(Args&&... args) noexcept { + return allocate(forward(args)...); +} + +/// @brief free a class. +/// @tparam KindClass the class type to allocate. +template <typename KindClass> +inline void release(KindClass ptr) { + if (!ptr) return; + + delete ptr; +} + +/// @brief destroy and free a class. +/// @note aborts on error. +/// @tparam KindClass the class type to allocate. +template <typename KindClass> +inline void release_nothrow(KindClass ptr) noexcept { + release(ptr); +} +} // namespace std::base_alloc diff --git a/include/LibC++/base_exception.h b/include/LibC++/base_exception.h new file mode 100644 index 0000000..8747688 --- /dev/null +++ b/include/LibC++/base_exception.h @@ -0,0 +1,37 @@ +/* ======================================== + + Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. + +======================================== */ + +#pragma once + +#include <LibC++/__abi.h> +#include <LibC++/base_process.h> +#include <LibC++/defines.h> +#include <iostream> + +/// @author Amlal El Mahrouss (amlal@nekernel.org) + +namespace std::base_exception::abi { +inline constexpr int __terminate_id = 33; + +/// @note This function is internal, don't call it. +extern void __unwind_object_list(); + +inline void __throw_general(const char* what) { + std::cout << "LibC++: Unwinding exception of kind: " << what << ", aborting here..." << std::endl; + __unwind_object_list(); + base_process::exit(__terminate_id); +} + +inline void __throw_domain_error(const char* what) { + __throw_general(what); + __builtin_unreachable(); // prevent from continuing. +} + +inline void __throw_bad_array_new_length(const char* what) { + __throw_general(what); + __builtin_unreachable(); // prevent from continuing. +} +} // namespace std::base_exception::abi diff --git a/include/LibC++/base_math.h b/include/LibC++/base_math.h new file mode 100644 index 0000000..60b260e --- /dev/null +++ b/include/LibC++/base_math.h @@ -0,0 +1,88 @@ +/* ======================================== + + Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. + +======================================== */ + +#pragma once + +#include <LibC++/defines.h> + +#ifndef NAN +#define NAN (__builtin_nanf("")) +#endif // !NAN + +/// @file Math.h +/// @brief Math functions. + +#ifdef __LIBCXX_USE_DOUBLE__ +typedef double real_type; +#else +typedef float real_type; +#endif + +namespace std::base_math { +inline constexpr static auto not_a_number = NAN; + +/// =========================================================== /// +/// @brief Power function, with Repeat argument. +/// =========================================================== /// +template <size_t Exponent> +inline real_type pow(real_type in) { + if (Exponent == 0) return 1; // Any number to the power of 0 is 1. + + if (Exponent == 1) return in; // Any number to the power of 1 is itself. + + size_t cnt = Exponent; + + real_type result = 1; + + for (auto i = 0; i < cnt; ++i) result *= in; + + return result; +} + +/// =========================================================== /// +/// @brief Square root function. +/// =========================================================== /// +inline real_type sqrt(real_type in) { + if (in == 0) return 0; + if (in == not_a_number) return not_a_number; + + auto constexpr const static Base = 2; + + auto x = in / Base; + + for (int i = 0; i < 10; ++i) { + x = (x + in / x) / Base; + } + + return x; +} + +/// =========================================================== /// +/// @brief Square of function, with Base template argument. +/// @param of Base argument to find the square of. +/// =========================================================== /// +template <size_t Base> +inline real_type surd(real_type in) { + if (in == 0) return 0; + if (in == 1) return 1; + + if (Base == 1) return in; + if (Base == 2) return sqrt(in); + + return not_a_number; +} + +/// =========================================================== /// +/// @brief Linear interpolation equation solver. +/// @param from where? +/// @param to to? +/// @param Updated diff value according to difference. +/// =========================================================== /// +inline real_type lerp(real_type to, real_type from, real_type stat) { + real_type diff = (to - from); + return from + (diff * stat); +} +} // namespace std::base_math diff --git a/include/LibC++/base_process.h b/include/LibC++/base_process.h new file mode 100644 index 0000000..cb25aa1 --- /dev/null +++ b/include/LibC++/base_process.h @@ -0,0 +1,45 @@ +/* ======================================== + + Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. + +======================================== */ + +#pragma once + +#include <LibC++/defines.h> + +__init_decl() + + /// @brief CRT exit, with exit code (!!! exits all threads. !!!) + /// @param code the exit code. + /// @return the return > 0 for non successful. + extern int exit_(int code); + +/// @brief CRT signal handler. +/// @param code the signal code. +extern void signal_(int code); + +extern void (*__atexit_cdecl_ptr)(void); +extern void (**__atexit_lst_ptr)(void); +extern size_t __atexit_lst_cnt; + +__fini_decl() + + /// @brief Standard C++ namespace + namespace std::base_process { + inline int signal(int code) { + signal_(code); + return -1; + } + + inline int32_t exit(const int32_t& code) { + for (auto idx = 0UL; idx < __atexit_lst_cnt; ++idx) { + __atexit_lst_ptr[idx](); + } + + if (__atexit_cdecl_ptr) __atexit_cdecl_ptr(); + + exit_(code); + return -1; + } +} // namespace std::base_process diff --git a/include/LibC++/defines.h b/include/LibC++/defines.h new file mode 100644 index 0000000..6aac009 --- /dev/null +++ b/include/LibC++/defines.h @@ -0,0 +1,81 @@ +/* ======================================== + + Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. + +======================================== */ + +#ifndef __NECTI_DEFINES_H__ +#define __NECTI_DEFINES_H__ + +#define __ATTRIBUTE(X) __attribute__((X)) + +typedef __SIZE_TYPE__ size_t; +typedef __INT64_TYPE__ ssize_t; +typedef __INT32_TYPE__ int32_t; + +typedef void* ptr_type; +typedef __SIZE_TYPE__ size_type; + +typedef __INT64_TYPE__ ptrdiff_t; +typedef size_t uintptr_t; +typedef void* voidptr_t; +typedef void* any_t; +typedef char* caddr_t; + +#ifndef NULL +#define NULL ((voidptr_t) 0) +#endif // !null + +#define __alloca(sz) __ck_alloca(sz) + +#define __deref(ptr) (*(ptr)) + +#ifdef __cplusplus +#define __init_decl() extern "C" { +#define __fini_decl() \ + } \ + ; +#else +#define __init_decl() +#define __fini_decl() +#endif + +#if __has_builtin(__builtin_alloca) +#define alloca(sz) __builtin_alloca(sz) +#ifdef __alloca +#undef __alloca +#endif +#define __alloca alloca +#else +#warning !! alloca not detected !! +#endif + +typedef long long off_t; +typedef unsigned long long uoff_t; + +typedef union float_cast { + struct { + unsigned int mantissa : 23; + unsigned int exponent : 8; + unsigned int sign : 1; + }; + + float f; +} __ATTRIBUTE(packed) float_cast_t; + +typedef union double_cast { + struct { + unsigned long long int mantissa : 52; + unsigned int exponent : 11; + unsigned int sign : 1; + }; + + double f; +} __ATTRIBUTE(packed) double_cast_t; + +namespace std { +struct placement_t; +struct nothrow_t; +} // namespace std + +#endif /* __NECTI_DEFINES_H__ */ diff --git a/include/LibC++/filesystem.h b/include/LibC++/filesystem.h new file mode 100644 index 0000000..4627c50 --- /dev/null +++ b/include/LibC++/filesystem.h @@ -0,0 +1,19 @@ +/* ======================================== + + Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. + +======================================== */ + +#ifndef __NECTI_FS_H__ +#define __NECTI_FS_H__ + +#include <LibC++/defines.h> + +namespace std { +class path; +class filesystem_error; +class directory_entry; +class directory_iterator; +} // namespace std + +#endif // __NECTI_FS_H__
\ No newline at end of file diff --git a/include/LibC++/make-stdcpp-hdrs.sh b/include/LibC++/make-stdcpp-hdrs.sh new file mode 100755 index 0000000..a3730de --- /dev/null +++ b/include/LibC++/make-stdcpp-hdrs.sh @@ -0,0 +1,13 @@ +#! /bin/sh + +outputDir=libc++/ + +mkdir -p $outputDir + +for f in *.h; do + +#This line splits the file name on the delimiter "." +baseName=`echo $f | cut -d "." -f 1` +cp $f $outputDir$baseName + +done diff --git a/include/LibC++/new.h b/include/LibC++/new.h new file mode 100644 index 0000000..faa9da4 --- /dev/null +++ b/include/LibC++/new.h @@ -0,0 +1,42 @@ +/* ======================================== + + Copyright (C) 2025, Amlal El Mahrouss, licensed under the Apache 2.0 license. + +======================================== */ + +#pragma once + +#include <LibC++/defines.h> + +namespace std { +struct nothrow_t final { + explicit nothrow_t() = default; + ~nothrow_t() = default; +}; + +struct placement_t final { + explicit placement_t() = default; + ~placement_t() = default; + + void* __base{}; + int32_t __align{}; + size_t __size{}; +}; +} // namespace std + +#ifndef __has_placement +#define placement +#endif + +void* operator new(size_t); +void* operator new[](size_t); + +void* operator new(size_t, const std::nothrow_t&) noexcept; +void* operator new(size_t, void*) noexcept; +void* operator new[](size_t, const std::nothrow_t&) noexcept; +void* operator new[](size_t, void*) noexcept; + +void operator delete(void*) noexcept; +void operator delete(void*, size_t) noexcept; + +void operator delete[](void*) noexcept; diff --git a/include/LibC++/utility.h b/include/LibC++/utility.h new file mode 100644 index 0000000..62096f5 --- /dev/null +++ b/include/LibC++/utility.h @@ -0,0 +1,30 @@ +/* ======================================== + + Copyright (C) 2024-2025 Amlal El Mahrouss, Licensed under the Apache 2.0 license. + +======================================== */ + +#ifndef LIBCXX_UTILITY_H +#define LIBCXX_UTILITY_H + +namespace std { +/// @brief Forward object. +/// @tparam Args the object type. +/// @param arg the object. +/// @return object's rvalue +template <typename Args> +inline auto forward(Args& arg) -> Args&& { + return static_cast<const Args&&>(arg); +} + +/// @brief Move object. +/// @tparam Args the object type. +/// @param arg the object. +/// @return object's rvalue +template <typename Args> +inline auto move(Args&& arg) -> Args&& { + return static_cast<Args&&>(arg); +} +} // namespace std + +#endif // LIBCXX_UTILITY_H diff --git a/include/ThirdParty/Dialogs/Dialogs.h b/include/ThirdParty/Dialogs/Dialogs.h new file mode 100644 index 0000000..f632026 --- /dev/null +++ b/include/ThirdParty/Dialogs/Dialogs.h @@ -0,0 +1,1738 @@ +// +// Portable File Dialogs +// +// Copyright © 2018–2022 Sam Hocevar <sam@hocevar.net> +// +// This library is free software. It comes without any warranty, to +// the extent permitted by applicable law. You can redistribute it +// and/or modify it under the terms of the Do What the Fuck You Want +// to Public License, Version 2, as published by the WTFPL Task Force. +// See http://www.wtfpl.net/ for more details. +// + +#pragma once + +#if _WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif +#include <commdlg.h> +#include <shellapi.h> +#include <shlobj.h> +#include <shobjidl.h> // IFileDialog +#include <strsafe.h> +#include <userenv.h> // GetUserProfileDirectory() +#include <windows.h> +#include <future> // std::async + +#elif __EMSCRIPTEN__ +#include <emscripten.h> + +#else +#ifndef _POSIX_C_SOURCE +#define _POSIX_C_SOURCE 2 // for popen() +#endif +#ifdef __APPLE__ +#ifndef _DARWIN_C_SOURCE +#define _DARWIN_C_SOURCE +#endif +#endif +#include <fcntl.h> // fcntl() +#include <pwd.h> // getpwnam() +#include <sys/stat.h> // stat() +#include <sys/wait.h> // waitpid() +#include <unistd.h> // read(), pipe(), dup2(), getuid() +#include <csignal> // ::kill, std::signal +#include <cstdio> // popen() +#include <cstdlib> // std::getenv() +#endif + +#include <chrono> // std::chrono +#include <iostream> // std::ostream +#include <map> // std::map +#include <memory> // std::shared_ptr +#include <regex> // std::regex +#include <set> // std::set +#include <string> // std::string +#include <thread> // std::mutex, std::this_thread + +// Versions of mingw64 g++ up to 9.3.0 do not have a complete IFileDialog +#ifndef PFD_HAS_IFILEDIALOG +#define PFD_HAS_IFILEDIALOG 1 +#if (defined __MINGW64__ || defined __MINGW32__) && defined __GXX_ABI_VERSION +#if __GXX_ABI_VERSION <= 1013 +#undef PFD_HAS_IFILEDIALOG +#define PFD_HAS_IFILEDIALOG 0 +#endif +#endif +#endif + +namespace pfd { + +enum class button { + cancel = -1, + ok, + yes, + no, + abort, + retry, + ignore, +}; + +enum class choice { + ok = 0, + ok_cancel, + yes_no, + yes_no_cancel, + retry_cancel, + abort_retry_ignore, +}; + +enum class icon { + info = 0, + warning, + error, + question, +}; + +// Additional option flags for various dialog constructors +enum class opt : uint8_t { + none = 0, + // For file open, allow multiselect. + multiselect = 0x1, + // For file save, force overwrite and disable the confirmation dialog. + force_overwrite = 0x2, + // For folder select, force path to be the provided argument instead + // of the last opened directory, which is the Microsoft-recommended, + // user-friendly behaviour. + force_path = 0x4, +}; + +inline opt operator|(opt a, opt b) { + return opt(uint8_t(a) | uint8_t(b)); +} +inline bool operator&(opt a, opt b) { + return bool(uint8_t(a) & uint8_t(b)); +} + +// The settings class, only exposing to the user a way to set verbose mode +// and to force a rescan of installed desktop helpers (zenity, kdialog…). +class settings { + public: + static bool available(); + + static void verbose(bool value); + static void rescan(); + + protected: + explicit settings(bool resync = false); + + bool check_program(std::string const& program); + + inline bool is_osascript() const; + inline bool is_zenity() const; + inline bool is_kdialog() const; + + enum class flag { + is_scanned = 0, + is_verbose, + + has_zenity, + has_matedialog, + has_qarma, + has_kdialog, + is_vista, + + max_flag, + }; + + // Static array of flags for internal state + bool const& flags(flag in_flag) const; + + // Non-const getter for the static array of flags + bool& flags(flag in_flag); +}; + +// Internal classes, not to be used by client applications +namespace internal { + + // Process wait timeout, in milliseconds + static int const default_wait_timeout = 20; + + class executor { + friend class dialog; + + public: + // High level function to get the result of a command + std::string result(int* exit_code = nullptr); + + // High level function to abort + bool kill(); + +#if _WIN32 + void start_func(std::function<std::string(int*)> const& fun); + static BOOL CALLBACK enum_windows_callback(HWND hwnd, LPARAM lParam); +#elif __EMSCRIPTEN__ + void start(int exit_code); +#else + void start_process(std::vector<std::string> const& command); +#endif + + ~executor(); + + protected: + bool ready(int timeout = default_wait_timeout); + void stop(); + + private: + bool m_running = false; + std::string m_stdout; + int m_exit_code = -1; +#if _WIN32 + std::future<std::string> m_future; + std::set<HWND> m_windows; + std::condition_variable m_cond; + std::mutex m_mutex; + DWORD m_tid; +#elif __EMSCRIPTEN__ || __NX__ + // FIXME: do something +#else + pid_t m_pid = 0; + int m_fd = -1; +#endif + }; + + class platform { + protected: +#if _WIN32 + // Helper class around LoadLibraryA() and GetProcAddress() with some safety + class dll { + public: + dll(std::string const& name); + ~dll(); + + template <typename T> + class proc { + public: + proc(dll const& lib, std::string const& sym) + : m_proc(reinterpret_cast<T*>((void*) ::GetProcAddress(lib.handle, sym.c_str()))) {} + + explicit operator bool() const { return m_proc != nullptr; } + operator T*() const { return m_proc; } + + private: + T* m_proc; + }; + + private: + HMODULE handle; + }; + + // Helper class around CoInitialize() and CoUnInitialize() + class ole32_dll : public dll { + public: + ole32_dll(); + ~ole32_dll(); + bool is_initialized(); + + private: + HRESULT m_state; + }; + + // Helper class around CreateActCtx() and ActivateActCtx() + class new_style_context { + public: + new_style_context(); + ~new_style_context(); + + private: + HANDLE create(); + ULONG_PTR m_cookie = 0; + }; +#endif + }; + + class dialog : protected settings, protected platform { + public: + bool ready(int timeout = default_wait_timeout) const; + bool kill() const; + + protected: + explicit dialog(); + + std::vector<std::string> desktop_helper() const; + static std::string buttons_to_name(choice _choice); + static std::string get_icon_name(icon _icon); + + std::string powershell_quote(std::string const& str) const; + std::string osascript_quote(std::string const& str) const; + std::string shell_quote(std::string const& str) const; + + // Keep handle to executing command + std::shared_ptr<executor> m_async; + }; + + class file_dialog : public dialog { + protected: + enum type { + open, + save, + folder, + }; + + file_dialog(type in_type, std::string const& title, std::string const& default_path = "", + std::vector<std::string> const& filters = {}, opt options = opt::none); + + protected: + std::string string_result(); + std::vector<std::string> vector_result(); + +#if _WIN32 + static int CALLBACK bffcallback(HWND hwnd, UINT uMsg, LPARAM, LPARAM pData); +#if PFD_HAS_IFILEDIALOG + std::string select_folder_vista(IFileDialog* ifd, bool force_path); +#endif + + std::wstring m_wtitle; + std::wstring m_wdefault_path; + + std::vector<std::string> m_vector_result; +#endif + }; + +} // namespace internal + +// +// The path class provides some platform-specific path constants +// + +class path : protected internal::platform { + public: + static std::string home(); + static std::string separator(); +}; + +// +// The notify widget +// + +class notify : public internal::dialog { + public: + notify(std::string const& title, std::string const& message, icon _icon = icon::info); +}; + +// +// The message widget +// + +class message : public internal::dialog { + public: + message(std::string const& title, std::string const& text, choice _choice = choice::ok_cancel, + icon _icon = icon::info); + + button result(); + + private: + // Some extra logic to map the exit code to button number + std::map<int, button> m_mappings; +}; + +// +// The open_file, save_file, and open_folder widgets +// + +class open_file : public internal::file_dialog { + public: + open_file(std::string const& title, std::string const& default_path = "", + std::vector<std::string> const& filters = {"All Files", "*"}, opt options = opt::none); + +#if defined(__has_cpp_attribute) +#if __has_cpp_attribute(deprecated) + // Backwards compatibility + [[deprecated("Use pfd::opt::multiselect instead of allow_multiselect")]] +#endif +#endif + open_file(std::string const& title, std::string const& default_path, + std::vector<std::string> const& filters, bool allow_multiselect); + + std::vector<std::string> result(); +}; + +class save_file : public internal::file_dialog { + public: + save_file(std::string const& title, std::string const& default_path = "", + std::vector<std::string> const& filters = {"All Files", "*"}, opt options = opt::none); + +#if defined(__has_cpp_attribute) +#if __has_cpp_attribute(deprecated) + // Backwards compatibility + [[deprecated("Use pfd::opt::force_overwrite instead of confirm_overwrite")]] +#endif +#endif + save_file(std::string const& title, std::string const& default_path, + std::vector<std::string> const& filters, bool confirm_overwrite); + + std::string result(); +}; + +class select_folder : public internal::file_dialog { + public: + select_folder(std::string const& title, std::string const& default_path = "", + opt options = opt::none); + + std::string result(); +}; + +// +// Below this are all the method implementations. You may choose to define the +// macro PFD_SKIP_IMPLEMENTATION everywhere before including this header except +// in one place. This may reduce compilation times. +// + +#if !defined PFD_SKIP_IMPLEMENTATION + +// internal free functions implementations + +namespace internal { + +#if _WIN32 + static inline std::wstring str2wstr(std::string const& str) { + int len = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int) str.size(), nullptr, 0); + std::wstring ret(len, '\0'); + MultiByteToWideChar(CP_UTF8, 0, str.c_str(), (int) str.size(), (LPWSTR) ret.data(), + (int) ret.size()); + return ret; + } + + static inline std::string wstr2str(std::wstring const& str) { + int len = WideCharToMultiByte(CP_UTF8, 0, str.c_str(), (int) str.size(), nullptr, 0, nullptr, + nullptr); + std::string ret(len, '\0'); + WideCharToMultiByte(CP_UTF8, 0, str.c_str(), (int) str.size(), (LPSTR) ret.data(), + (int) ret.size(), nullptr, nullptr); + return ret; + } + + static inline bool is_vista() { + OSVERSIONINFOEXW osvi; + memset(&osvi, 0, sizeof(osvi)); + DWORDLONG const mask = VerSetConditionMask( + VerSetConditionMask(VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL), + VER_MINORVERSION, VER_GREATER_EQUAL), + VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL); + osvi.dwOSVersionInfoSize = sizeof(osvi); + osvi.dwMajorVersion = HIBYTE(_WIN32_WINNT_VISTA); + osvi.dwMinorVersion = LOBYTE(_WIN32_WINNT_VISTA); + osvi.wServicePackMajor = 0; + + return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, + mask) != FALSE; + } +#endif + + // This is necessary until C++20 which will have std::string::ends_with() etc. + + static inline bool ends_with(std::string const& str, std::string const& suffix) { + return suffix.size() <= str.size() && + str.compare(str.size() - suffix.size(), suffix.size(), suffix) == 0; + } + + static inline bool starts_with(std::string const& str, std::string const& prefix) { + return prefix.size() <= str.size() && str.compare(0, prefix.size(), prefix) == 0; + } + + // This is necessary until C++17 which will have std::filesystem::is_directory + + static inline bool is_directory(std::string const& path) { +#if _WIN32 + auto attr = GetFileAttributesA(path.c_str()); + return attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY); +#elif __EMSCRIPTEN__ + // TODO + return false; +#else + struct stat s; + return stat(path.c_str(), &s) == 0 && S_ISDIR(s.st_mode); +#endif + } + + // This is necessary because getenv is not thread-safe + + static inline std::string getenv(std::string const& str) { +#if _MSC_VER + char* buf = nullptr; + size_t size = 0; + if (_dupenv_s(&buf, &size, str.c_str()) == 0 && buf) { + std::string ret(buf); + free(buf); + return ret; + } + return ""; +#else + auto buf = std::getenv(str.c_str()); + return buf ? buf : ""; +#endif + } + +} // namespace internal + +// settings implementation + +inline settings::settings(bool resync) { + flags(flag::is_scanned) &= !resync; + + if (flags(flag::is_scanned)) return; + + auto pfd_verbose = internal::getenv("PFD_VERBOSE"); + auto match_no = std::regex("(|0|no|false)", std::regex_constants::icase); + if (!std::regex_match(pfd_verbose, match_no)) flags(flag::is_verbose) = true; + +#if _WIN32 + flags(flag::is_vista) = internal::is_vista(); +#elif !__APPLE__ + flags(flag::has_zenity) = check_program("zenity"); + flags(flag::has_matedialog) = check_program("matedialog"); + flags(flag::has_qarma) = check_program("qarma"); + flags(flag::has_kdialog) = check_program("kdialog"); + + // If multiple helpers are available, try to default to the best one + if (flags(flag::has_zenity) && flags(flag::has_kdialog)) { + auto desktop_name = internal::getenv("XDG_SESSION_DESKTOP"); + if (desktop_name == std::string("gnome")) + flags(flag::has_kdialog) = false; + else if (desktop_name == std::string("KDE")) + flags(flag::has_zenity) = false; + } +#endif + + flags(flag::is_scanned) = true; +} + +inline bool settings::available() { +#if _WIN32 + return true; +#elif __APPLE__ + return true; +#elif __EMSCRIPTEN__ + // FIXME: Return true after implementation is complete. + return false; +#else + settings tmp; + return tmp.flags(flag::has_zenity) || tmp.flags(flag::has_matedialog) || + tmp.flags(flag::has_qarma) || tmp.flags(flag::has_kdialog); +#endif +} + +inline void settings::verbose(bool value) { + settings().flags(flag::is_verbose) = value; +} + +inline void settings::rescan() { + settings(/* resync = */ true); +} + +// Check whether a program is present using “which”. +inline bool settings::check_program(std::string const& program) { +#if _WIN32 + (void) program; + return false; +#elif __EMSCRIPTEN__ + (void) program; + return false; +#else + int exit_code = -1; + internal::executor async; + async.start_process({"/bin/sh", "-c", "which " + program}); + async.result(&exit_code); + return exit_code == 0; +#endif +} + +inline bool settings::is_osascript() const { +#if __APPLE__ + return true; +#else + return false; +#endif +} + +inline bool settings::is_zenity() const { + return flags(flag::has_zenity) || flags(flag::has_matedialog) || flags(flag::has_qarma); +} + +inline bool settings::is_kdialog() const { + return flags(flag::has_kdialog); +} + +inline bool const& settings::flags(flag in_flag) const { + static bool flags[size_t(flag::max_flag)]; + return flags[size_t(in_flag)]; +} + +inline bool& settings::flags(flag in_flag) { + return const_cast<bool&>(static_cast<settings const*>(this)->flags(in_flag)); +} + +// path implementation +inline std::string path::home() { +#if _WIN32 + // First try the USERPROFILE environment variable + auto user_profile = internal::getenv("USERPROFILE"); + if (user_profile.size() > 0) return user_profile; + // Otherwise, try GetUserProfileDirectory() + HANDLE token = nullptr; + DWORD len = MAX_PATH; + char buf[MAX_PATH] = {'\0'}; + if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) { + dll userenv("userenv.dll"); + dll::proc<BOOL WINAPI(HANDLE, LPSTR, LPDWORD)> get_user_profile_directory( + userenv, "GetUserProfileDirectoryA"); + get_user_profile_directory(token, buf, &len); + CloseHandle(token); + if (*buf) return buf; + } +#elif __EMSCRIPTEN__ + return "/"; +#else + // First try the HOME environment variable + auto home = internal::getenv("HOME"); + if (home.size() > 0) return home; + // Otherwise, try getpwuid_r() + size_t len = 4096; +#if defined(_SC_GETPW_R_SIZE_MAX) + auto size_max = sysconf(_SC_GETPW_R_SIZE_MAX); + if (size_max != -1) len = size_t(size_max); +#endif + std::vector<char> buf(len); + struct passwd pwd, *result; + if (getpwuid_r(getuid(), &pwd, buf.data(), buf.size(), &result) == 0) return result->pw_dir; +#endif + return "/"; +} + +inline std::string path::separator() { +#if _WIN32 + return "\\"; +#else + return "/"; +#endif +} + +// executor implementation + +inline std::string internal::executor::result(int* exit_code /* = nullptr */) { + stop(); + if (exit_code) *exit_code = m_exit_code; + return m_stdout; +} + +inline bool internal::executor::kill() { +#if _WIN32 + if (m_future.valid()) { + // Close all windows that weren’t open when we started the future + auto previous_windows = m_windows; + EnumWindows(&enum_windows_callback, (LPARAM) this); + for (auto hwnd : m_windows) + if (previous_windows.find(hwnd) == previous_windows.end()) { + SendMessage(hwnd, WM_CLOSE, 0, 0); + // Also send IDNO in case of a Yes/No or Abort/Retry/Ignore messagebox + SendMessage(hwnd, WM_COMMAND, IDNO, 0); + } + } +#elif __EMSCRIPTEN__ || __NX__ + // FIXME: do something + return false; // cannot kill +#else + ::kill(m_pid, SIGKILL); +#endif + stop(); + return true; +} + +#if _WIN32 +inline BOOL CALLBACK internal::executor::enum_windows_callback(HWND hwnd, LPARAM lParam) { + auto that = (executor*) lParam; + + DWORD pid; + auto tid = GetWindowThreadProcessId(hwnd, &pid); + if (tid == that->m_tid) that->m_windows.insert(hwnd); + return TRUE; +} +#endif + +#if _WIN32 +inline void internal::executor::start_func(std::function<std::string(int*)> const& fun) { + stop(); + + auto trampoline = [fun, this]() { + // Save our thread id so that the caller can cancel us + m_tid = GetCurrentThreadId(); + EnumWindows(&enum_windows_callback, (LPARAM) this); + m_cond.notify_all(); + return fun(&m_exit_code); + }; + + std::unique_lock<std::mutex> lock(m_mutex); + m_future = std::async(std::launch::async, trampoline); + m_cond.wait(lock); + m_running = true; +} + +#elif __EMSCRIPTEN__ +inline void internal::executor::start(int exit_code) { + m_exit_code = exit_code; +} + +#else +inline void internal::executor::start_process(std::vector<std::string> const& command) { + stop(); + m_stdout.clear(); + m_exit_code = -1; + + int in[2], out[2]; + if (pipe(in) != 0 || pipe(out) != 0) return; + + m_pid = fork(); + if (m_pid < 0) return; + + close(in[m_pid ? 0 : 1]); + close(out[m_pid ? 1 : 0]); + + if (m_pid == 0) { + dup2(in[0], STDIN_FILENO); + dup2(out[1], STDOUT_FILENO); + + // Ignore stderr so that it doesn’t pollute the console (e.g. GTK+ errors from zenity) + int fd = open("/src/null", O_WRONLY); + dup2(fd, STDERR_FILENO); + close(fd); + + std::vector<char*> args; + std::transform(command.cbegin(), command.cend(), std::back_inserter(args), + [](std::string const& s) { return const_cast<char*>(s.c_str()); }); + args.push_back(nullptr); // null-terminate argv[] + + execvp(args[0], args.data()); + exit(1); + } + + close(in[1]); + m_fd = out[0]; + auto flags = fcntl(m_fd, F_GETFL); + fcntl(m_fd, F_SETFL, flags | O_NONBLOCK); + + m_running = true; +} +#endif + +inline internal::executor::~executor() { + stop(); +} + +inline bool internal::executor::ready(int timeout /* = default_wait_timeout */) { + if (!m_running) return true; + +#if _WIN32 + if (m_future.valid()) { + auto status = m_future.wait_for(std::chrono::milliseconds(timeout)); + if (status != std::future_status::ready) { + // On Windows, we need to run the message pump. If the async + // thread uses a Windows API dialog, it may be attached to the + // main thread and waiting for messages that only we can dispatch. + MSG msg; + while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + return false; + } + + m_stdout = m_future.get(); + } +#elif __EMSCRIPTEN__ || __NX__ + // FIXME: do something + (void) timeout; +#else + char buf[BUFSIZ]; + ssize_t received = read(m_fd, buf, BUFSIZ); // Flawfinder: ignore + if (received > 0) { + m_stdout += std::string(buf, received); + return false; + } + + // Reap child process if it is dead. It is possible that the system has already reaped it + // (this happens when the calling application handles or ignores SIG_CHLD) and results in + // waitpid() failing with ECHILD. Otherwise we assume the child is running and we sleep for + // a little while. + int status; + pid_t child = waitpid(m_pid, &status, WNOHANG); + if (child != m_pid && (child >= 0 || errno != ECHILD)) { + // FIXME: this happens almost always at first iteration + std::this_thread::sleep_for(std::chrono::milliseconds(timeout)); + return false; + } + + close(m_fd); + m_exit_code = WEXITSTATUS(status); +#endif + + m_running = false; + return true; +} + +inline void internal::executor::stop() { + // Loop until the user closes the dialog + while (!ready()); +} + +// dll implementation + +#if _WIN32 +inline internal::platform::dll::dll(std::string const& name) + : handle(::LoadLibraryA(name.c_str())) {} + +inline internal::platform::dll::~dll() { + if (handle) ::FreeLibrary(handle); +} +#endif // _WIN32 + +// ole32_dll implementation + +#if _WIN32 +inline internal::platform::ole32_dll::ole32_dll() : dll("ole32.dll") { + // Use COINIT_MULTITHREADED because COINIT_APARTMENTTHREADED causes crashes. + // See https://github.com/samhocevar/portable-file-dialogs/issues/51 + auto coinit = proc<HRESULT WINAPI(LPVOID, DWORD)>(*this, "CoInitializeEx"); + m_state = coinit(nullptr, COINIT_MULTITHREADED); +} + +inline internal::platform::ole32_dll::~ole32_dll() { + if (is_initialized()) proc<void WINAPI()>(*this, "CoUninitialize")(); +} + +inline bool internal::platform::ole32_dll::is_initialized() { + return m_state == S_OK || m_state == S_FALSE; +} +#endif + +// new_style_context implementation + +#if _WIN32 +inline internal::platform::new_style_context::new_style_context() { + // Only create one activation context for the whole app lifetime. + static HANDLE hctx = create(); + + if (hctx != INVALID_HANDLE_VALUE) ActivateActCtx(hctx, &m_cookie); +} + +inline internal::platform::new_style_context::~new_style_context() { + DeactivateActCtx(0, m_cookie); +} + +inline HANDLE internal::platform::new_style_context::create() { + // This “hack” seems to be necessary for this code to work on windows XP. + // Without it, dialogs do not show and close immediately. GetError() + // returns 0 so I don’t know what causes this. I was not able to reproduce + // this behavior on Windows 7 and 10 but just in case, let it be here for + // those versions too. + // This hack is not required if other dialogs are used (they load comdlg32 + // automatically), only if message boxes are used. + dll comdlg32("comdlg32.dll"); + + // Using approach as shown here: https://stackoverflow.com/a/10444161 + UINT len = ::GetSystemDirectoryA(nullptr, 0); + std::string sys_dir(len, '\0'); + ::GetSystemDirectoryA(&sys_dir[0], len); + + ACTCTXA act_ctx = { + // Do not set flag ACTCTX_FLAG_SET_PROCESS_DEFAULT, since it causes a + // crash with error “default context is already set”. + sizeof(act_ctx), + ACTCTX_FLAG_RESOURCE_NAME_VALID | ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID, + "shell32.dll", + 0, + 0, + sys_dir.c_str(), + (LPCSTR) 124, + nullptr, + 0, + }; + + return ::CreateActCtxA(&act_ctx); +} +#endif // _WIN32 + +// dialog implementation + +inline bool internal::dialog::ready(int timeout /* = default_wait_timeout */) const { + return m_async->ready(timeout); +} + +inline bool internal::dialog::kill() const { + return m_async->kill(); +} + +inline internal::dialog::dialog() : m_async(std::make_shared<executor>()) {} + +inline std::vector<std::string> internal::dialog::desktop_helper() const { +#if __APPLE__ + return {"osascript"}; +#else + return {flags(flag::has_zenity) ? "zenity" + : flags(flag::has_matedialog) ? "matedialog" + : flags(flag::has_qarma) ? "qarma" + : flags(flag::has_kdialog) ? "kdialog" + : "echo"}; +#endif +} + +inline std::string internal::dialog::buttons_to_name(choice _choice) { + switch (_choice) { + case choice::ok_cancel: + return "okcancel"; + case choice::yes_no: + return "yesno"; + case choice::yes_no_cancel: + return "yesnocancel"; + case choice::retry_cancel: + return "retrycancel"; + case choice::abort_retry_ignore: + return "abortretryignore"; + /* case choice::ok: */ default: + return "ok"; + } +} + +inline std::string internal::dialog::get_icon_name(icon _icon) { + switch (_icon) { + case icon::warning: + return "warning"; + case icon::error: + return "error"; + case icon::question: + return "question"; + // Zenity wants "information" but WinForms wants "info" + /* case icon::info: */ default: +#if _WIN32 + return "info"; +#else + return "information"; +#endif + } +} + +// This is only used for debugging purposes +inline std::ostream& operator<<(std::ostream& s, std::vector<std::string> const& v) { + int not_first = 0; + for (auto& e : v) s << (not_first++ ? " " : "") << e; + return s; +} + +// Properly quote a string for Powershell: replace ' or " with '' or "" +// FIXME: we should probably get rid of newlines! +// FIXME: the \" sequence seems unsafe, too! +// XXX: this is no longer used but I would like to keep it around just in case +inline std::string internal::dialog::powershell_quote(std::string const& str) const { + return "'" + std::regex_replace(str, std::regex("['\"]"), "$&$&") + "'"; +} + +// Properly quote a string for osascript: replace \ or " with \\ or \" +// XXX: this also used to replace ' with \' when popen was used, but it would be +// smarter to do shell_quote(osascript_quote(...)) if this is needed again. +inline std::string internal::dialog::osascript_quote(std::string const& str) const { + return "\"" + std::regex_replace(str, std::regex("[\\\\\"]"), "\\$&") + "\""; +} + +// Properly quote a string for the shell: just replace ' with '\'' +// XXX: this is no longer used but I would like to keep it around just in case +inline std::string internal::dialog::shell_quote(std::string const& str) const { + return "'" + std::regex_replace(str, std::regex("'"), "'\\''") + "'"; +} + +// file_dialog implementation + +inline internal::file_dialog::file_dialog(type in_type, std::string const& title, + std::string const& default_path /* = "" */, + std::vector<std::string> const& filters /* = {} */, + opt options /* = opt::none */) { +#if _WIN32 + std::string filter_list; + std::regex whitespace(" *"); + for (size_t i = 0; i + 1 < filters.size(); i += 2) { + filter_list += filters[i] + '\0'; + filter_list += std::regex_replace(filters[i + 1], whitespace, ";") + '\0'; + } + filter_list += '\0'; + + m_async->start_func( + [this, in_type, title, default_path, filter_list, options](int* exit_code) -> std::string { + (void) exit_code; + m_wtitle = internal::str2wstr(title); + m_wdefault_path = internal::str2wstr(default_path); + auto wfilter_list = internal::str2wstr(filter_list); + + // Initialise COM. This is required for the new folder selection window, + // (see https://github.com/samhocevar/portable-file-dialogs/pull/21) + // and to avoid random crashes with GetOpenFileNameW() (see + // https://github.com/samhocevar/portable-file-dialogs/issues/51) + ole32_dll ole32; + + // Folder selection uses a different method + if (in_type == type::folder) { +#if PFD_HAS_IFILEDIALOG + if (flags(flag::is_vista)) { + // On Vista and higher we should be able to use IFileDialog for folder selection + IFileDialog* ifd; + HRESULT hr = dll::proc<HRESULT WINAPI(REFCLSID, LPUNKNOWN, DWORD, REFIID, LPVOID*)>( + ole32, "CoCreateInstance")(CLSID_FileOpenDialog, nullptr, CLSCTX_INPROC_SERVER, + IID_PPV_ARGS(&ifd)); + + // In case CoCreateInstance fails (which it should not), try legacy approach + if (SUCCEEDED(hr)) return select_folder_vista(ifd, options & opt::force_path); + } +#endif + + BROWSEINFOW bi; + memset(&bi, 0, sizeof(bi)); + + bi.lpfn = &bffcallback; + bi.lParam = (LPARAM) this; + + if (flags(flag::is_vista)) { + if (ole32.is_initialized()) bi.ulFlags |= BIF_NEWDIALOGSTYLE; + bi.ulFlags |= BIF_EDITBOX; + bi.ulFlags |= BIF_STATUSTEXT; + } + + auto* list = SHBrowseForFolderW(&bi); + std::string ret; + if (list) { + auto buffer = new wchar_t[MAX_PATH]; + SHGetPathFromIDListW(list, buffer); + dll::proc<void WINAPI(LPVOID)>(ole32, "CoTaskMemFree")(list); + ret = internal::wstr2str(buffer); + delete[] buffer; + } + return ret; + } + + OPENFILENAMEW ofn; + memset(&ofn, 0, sizeof(ofn)); + ofn.lStructSize = sizeof(OPENFILENAMEW); + ofn.hwndOwner = GetActiveWindow(); + + ofn.lpstrFilter = wfilter_list.c_str(); + + auto woutput = std::wstring(MAX_PATH * 256, L'\0'); + ofn.lpstrFile = (LPWSTR) woutput.data(); + ofn.nMaxFile = (DWORD) woutput.size(); + if (!m_wdefault_path.empty()) { + // If a directory was provided, use it as the initial directory. If + // a valid path was provided, use it as the initial file. Otherwise, + // let the Windows API decide. + auto path_attr = GetFileAttributesW(m_wdefault_path.c_str()); + if (path_attr != INVALID_FILE_ATTRIBUTES && (path_attr & FILE_ATTRIBUTE_DIRECTORY)) + ofn.lpstrInitialDir = m_wdefault_path.c_str(); + else if (m_wdefault_path.size() <= woutput.size()) + // second argument is size of buffer, not length of string + StringCchCopyW(ofn.lpstrFile, MAX_PATH * 256 + 1, m_wdefault_path.c_str()); + else { + ofn.lpstrFileTitle = (LPWSTR) m_wdefault_path.data(); + ofn.nMaxFileTitle = (DWORD) m_wdefault_path.size(); + } + } + ofn.lpstrTitle = m_wtitle.c_str(); + ofn.Flags = OFN_NOCHANGEDIR | OFN_EXPLORER; + + dll comdlg32("comdlg32.dll"); + + // Apply new visual style (required for windows XP) + new_style_context ctx; + + if (in_type == type::save) { + if (!(options & opt::force_overwrite)) ofn.Flags |= OFN_OVERWRITEPROMPT; + + dll::proc<BOOL WINAPI(LPOPENFILENAMEW)> get_save_file_name(comdlg32, "GetSaveFileNameW"); + if (get_save_file_name(&ofn) == 0) return ""; + return internal::wstr2str(woutput.c_str()); + } else { + if (options & opt::multiselect) ofn.Flags |= OFN_ALLOWMULTISELECT; + ofn.Flags |= OFN_PATHMUSTEXIST; + + dll::proc<BOOL WINAPI(LPOPENFILENAMEW)> get_open_file_name(comdlg32, "GetOpenFileNameW"); + if (get_open_file_name(&ofn) == 0) return ""; + } + + std::string prefix; + for (wchar_t const* p = woutput.c_str(); *p;) { + auto filename = internal::wstr2str(p); + p += wcslen(p); + // In multiselect mode, we advance p one wchar further and + // check for another filename. If there is one and the + // prefix is empty, it means we just read the prefix. + if ((options & opt::multiselect) && *++p && prefix.empty()) { + prefix = filename + "/"; + continue; + } + + m_vector_result.push_back(prefix + filename); + } + + return ""; + }); +#elif __EMSCRIPTEN__ + // FIXME: do something + (void) in_type; + (void) title; + (void) default_path; + (void) filters; + (void) options; +#else + auto command = desktop_helper(); + + if (is_osascript()) { + std::string script = "set ret to choose"; + switch (in_type) { + case type::save: + script += " file name"; + break; + case type::open: + default: + script += " file"; + if (options & opt::multiselect) script += " with multiple selections allowed"; + break; + case type::folder: + script += " folder"; + break; + } + + if (default_path.size()) { + if (in_type == type::folder || is_directory(default_path)) + script += " default location "; + else + script += " default name "; + script += osascript_quote(default_path); + } + + script += " with prompt " + osascript_quote(title); + + if (in_type == type::open) { + // Concatenate all user-provided filter patterns + std::string patterns; + for (size_t i = 0; i < filters.size() / 2; ++i) patterns += " " + filters[2 * i + 1]; + + // Split the pattern list to check whether "*" is in there; if it + // is, we have to disable filters because there is no mechanism in + // OS X for the user to override the filter. + std::regex sep("\\s+"); + std::string filter_list; + bool has_filter = true; + std::sregex_token_iterator iter(patterns.begin(), patterns.end(), sep, -1); + std::sregex_token_iterator end; + for (; iter != end; ++iter) { + auto pat = iter->str(); + if (pat == "*" || pat == "*.*") + has_filter = false; + else if (internal::starts_with(pat, "*.")) + filter_list += "," + osascript_quote(pat.substr(2, pat.size() - 2)); + } + + if (has_filter && filter_list.size() > 0) { + // There is a weird AppleScript bug where file extensions of length != 3 are + // ignored, e.g. type{"txt"} works, but type{"json"} does not. Fortunately if + // the whole list starts with a 3-character extension, everything works again. + // We use "///" for such an extension because we are sure it cannot appear in + // an actual filename. + script += " of type {\"///\"" + filter_list + "}"; + } + } + + if (in_type == type::open && (options & opt::multiselect)) { + script += "\nset s to \"\""; + script += "\nrepeat with i in ret"; + script += "\n set s to s & (POSIX path of i) & \"\\n\""; + script += "\nend repeat"; + script += "\ncopy s to stdout"; + } else { + script += "\nPOSIX path of ret"; + } + + command.push_back("-e"); + command.push_back(script); + } else if (is_zenity()) { + command.push_back("--file-selection"); + + // If the default path is a directory, make sure it ends with "/" otherwise zenity will + // open the file dialog in the parent directory. + auto filename_arg = "--filename=" + default_path; + if (in_type != type::folder && !ends_with(default_path, "/") && + internal::is_directory(default_path)) + filename_arg += "/"; + command.push_back(filename_arg); + + command.push_back("--title"); + command.push_back(title); + command.push_back("--separator=\n"); + + for (size_t i = 0; i < filters.size() / 2; ++i) { + command.push_back("--file-filter"); + command.push_back(filters[2 * i] + "|" + filters[2 * i + 1]); + } + + if (in_type == type::save) command.push_back("--save"); + if (in_type == type::folder) command.push_back("--directory"); + if (!(options & opt::force_overwrite)) command.push_back("--confirm-overwrite"); + if (options & opt::multiselect) command.push_back("--multiple"); + } else if (is_kdialog()) { + switch (in_type) { + case type::save: + command.push_back("--getsavefilename"); + break; + case type::open: + command.push_back("--getopenfilename"); + break; + case type::folder: + command.push_back("--getexistingdirectory"); + break; + } + if (options & opt::multiselect) { + command.push_back("--multiple"); + command.push_back("--separate-output"); + } + + command.push_back(default_path); + + std::string filter; + for (size_t i = 0; i < filters.size() / 2; ++i) + filter += (i == 0 ? "" : " | ") + filters[2 * i] + "(" + filters[2 * i + 1] + ")"; + command.push_back(filter); + + command.push_back("--title"); + command.push_back(title); + } + + if (flags(flag::is_verbose)) std::cerr << "pfd: " << command << std::endl; + + m_async->start_process(command); +#endif +} + +inline std::string internal::file_dialog::string_result() { +#if _WIN32 + return m_async->result(); +#else + auto ret = m_async->result(); + // Strip potential trailing newline (zenity). Also strip trailing slash + // added by osascript for consistency with other backends. + while (!ret.empty() && (ret.back() == '\n' || ret.back() == '/')) ret.pop_back(); + return ret; +#endif +} + +inline std::vector<std::string> internal::file_dialog::vector_result() { +#if _WIN32 + m_async->result(); + return m_vector_result; +#else + std::vector<std::string> ret; + auto result = m_async->result(); + for (;;) { + // Split result along newline characters + auto i = result.find('\n'); + if (i == 0 || i == std::string::npos) break; + ret.push_back(result.substr(0, i)); + result = result.substr(i + 1, result.size()); + } + return ret; +#endif +} + +#if _WIN32 +// Use a static function to pass as BFFCALLBACK for legacy folder select +inline int CALLBACK internal::file_dialog::bffcallback(HWND hwnd, UINT uMsg, LPARAM, LPARAM pData) { + auto inst = (file_dialog*) pData; + switch (uMsg) { + case BFFM_INITIALIZED: + SendMessage(hwnd, BFFM_SETSELECTIONW, TRUE, (LPARAM) inst->m_wdefault_path.c_str()); + break; + } + return 0; +} + +#if PFD_HAS_IFILEDIALOG +inline std::string internal::file_dialog::select_folder_vista(IFileDialog* ifd, bool force_path) { + std::string result; + + IShellItem* folder; + + // Load library at runtime so app doesn't link it at load time (which will fail on windows XP) + dll shell32("shell32.dll"); + dll::proc<HRESULT WINAPI(PCWSTR, IBindCtx*, REFIID, void**)> create_item( + shell32, "SHCreateItemFromParsingName"); + + if (!create_item) return ""; + + auto hr = create_item(m_wdefault_path.c_str(), nullptr, IID_PPV_ARGS(&folder)); + + // Set default folder if found. This only sets the default folder. If + // Windows has any info about the most recently selected folder, it + // will display it instead. Generally, calling SetFolder() to set the + // current directory “is not a good or expected user experience and + // should therefore be avoided”: + // https://docs.microsoft.com/windows/win32/api/shobjidl_core/nf-shobjidl_core-ifiledialog-setfolder + if (SUCCEEDED(hr)) { + if (force_path) + ifd->SetFolder(folder); + else + ifd->SetDefaultFolder(folder); + folder->Release(); + } + + // Set the dialog title and option to select folders + ifd->SetOptions(FOS_PICKFOLDERS | FOS_FORCEFILESYSTEM); + ifd->SetTitle(m_wtitle.c_str()); + + hr = ifd->Show(GetActiveWindow()); + if (SUCCEEDED(hr)) { + IShellItem* item; + hr = ifd->GetResult(&item); + if (SUCCEEDED(hr)) { + wchar_t* wname = nullptr; + // This is unlikely to fail because we use FOS_FORCEFILESYSTEM, but try + // to output a debug message just in case. + if (SUCCEEDED(item->GetDisplayName(SIGDN_FILESYSPATH, &wname))) { + result = internal::wstr2str(std::wstring(wname)); + dll::proc<void WINAPI(LPVOID)>(ole32_dll(), "CoTaskMemFree")(wname); + } else { + if (SUCCEEDED(item->GetDisplayName(SIGDN_NORMALDISPLAY, &wname))) { + auto name = internal::wstr2str(std::wstring(wname)); + dll::proc<void WINAPI(LPVOID)>(ole32_dll(), "CoTaskMemFree")(wname); + std::cerr << "pfd: failed to get path for " << name << std::endl; + } else + std::cerr << "pfd: item of unknown type selected" << std::endl; + } + + item->Release(); + } + } + + ifd->Release(); + + return result; +} +#endif +#endif + +// notify implementation + +inline notify::notify(std::string const& title, std::string const& message, + icon _icon /* = icon::info */) { + if (_icon == icon::question) // Not supported by notifications + _icon = icon::info; + +#if _WIN32 + // Use a static shared pointer for notify_icon so that we can delete + // it whenever we need to display a new one, and we can also wait + // until the program has finished running. + struct notify_icon_data : public NOTIFYICONDATAW { + ~notify_icon_data() { Shell_NotifyIconW(NIM_DELETE, this); } + }; + + static std::shared_ptr<notify_icon_data> nid; + + // Release the previous notification icon, if any, and allocate a new + // one. Note that std::make_shared() does value initialization, so there + // is no need to memset the structure. + nid = nullptr; + nid = std::make_shared<notify_icon_data>(); + + // For XP support + nid->cbSize = NOTIFYICONDATAW_V2_SIZE; + nid->hWnd = nullptr; + nid->uID = 0; + + // Flag Description: + // - NIF_ICON The hIcon member is valid. + // - NIF_MESSAGE The uCallbackMessage member is valid. + // - NIF_TIP The szTip member is valid. + // - NIF_STATE The dwState and dwStateMask members are valid. + // - NIF_INFO Use a balloon ToolTip instead of a standard ToolTip. The szInfo, uTimeout, + // szInfoTitle, and dwInfoFlags members are valid. + // - NIF_GUID Reserved. + nid->uFlags = NIF_MESSAGE | NIF_ICON | NIF_INFO; + + // Flag Description + // - NIIF_ERROR An error icon. + // - NIIF_INFO An information icon. + // - NIIF_NONE No icon. + // - NIIF_WARNING A warning icon. + // - NIIF_ICON_MASK Version 6.0. Reserved. + // - NIIF_NOSOUND Version 6.0. Do not play the associated sound. Applies only to balloon + // ToolTips + switch (_icon) { + case icon::warning: + nid->dwInfoFlags = NIIF_WARNING; + break; + case icon::error: + nid->dwInfoFlags = NIIF_ERROR; + break; + /* case icon::info: */ default: + nid->dwInfoFlags = NIIF_INFO; + break; + } + + ENUMRESNAMEPROC icon_enum_callback = [](HMODULE, LPCTSTR, LPTSTR lpName, + LONG_PTR lParam) -> BOOL { + ((NOTIFYICONDATAW*) lParam)->hIcon = ::LoadIcon(GetModuleHandle(nullptr), lpName); + return false; + }; + + nid->hIcon = ::LoadIcon(nullptr, IDI_APPLICATION); + ::EnumResourceNames(nullptr, RT_GROUP_ICON, icon_enum_callback, (LONG_PTR) nid.get()); + + nid->uTimeout = 5000; + + StringCchCopyW(nid->szInfoTitle, ARRAYSIZE(nid->szInfoTitle), internal::str2wstr(title).c_str()); + StringCchCopyW(nid->szInfo, ARRAYSIZE(nid->szInfo), internal::str2wstr(message).c_str()); + + // Display the new icon + Shell_NotifyIconW(NIM_ADD, nid.get()); +#elif __EMSCRIPTEN__ + // FIXME: do something + (void) title; + (void) message; +#else + auto command = desktop_helper(); + + if (is_osascript()) { + command.push_back("-e"); + command.push_back("display notification " + osascript_quote(message) + " with title " + + osascript_quote(title)); + } else if (is_zenity()) { + command.push_back("--notification"); + command.push_back("--window-icon"); + command.push_back(get_icon_name(_icon)); + command.push_back("--text"); + command.push_back(title + "\n" + message); + } else if (is_kdialog()) { + command.push_back("--icon"); + command.push_back(get_icon_name(_icon)); + command.push_back("--title"); + command.push_back(title); + command.push_back("--passivepopup"); + command.push_back(message); + command.push_back("5"); + } + + if (flags(flag::is_verbose)) std::cerr << "pfd: " << command << std::endl; + + m_async->start_process(command); +#endif +} + +// message implementation + +inline message::message(std::string const& title, std::string const& text, + choice _choice /* = choice::ok_cancel */, icon _icon /* = icon::info */) { +#if _WIN32 + // Use MB_SYSTEMMODAL rather than MB_TOPMOST to ensure the message window is brought + // to front. See https://github.com/samhocevar/portable-file-dialogs/issues/52 + UINT style = MB_SYSTEMMODAL; + switch (_icon) { + case icon::warning: + style |= MB_ICONWARNING; + break; + case icon::error: + style |= MB_ICONERROR; + break; + case icon::question: + style |= MB_ICONQUESTION; + break; + /* case icon::info: */ default: + style |= MB_ICONINFORMATION; + break; + } + + switch (_choice) { + case choice::ok_cancel: + style |= MB_OKCANCEL; + break; + case choice::yes_no: + style |= MB_YESNO; + break; + case choice::yes_no_cancel: + style |= MB_YESNOCANCEL; + break; + case choice::retry_cancel: + style |= MB_RETRYCANCEL; + break; + case choice::abort_retry_ignore: + style |= MB_ABORTRETRYIGNORE; + break; + /* case choice::ok: */ default: + style |= MB_OK; + break; + } + + m_mappings[IDCANCEL] = button::cancel; + m_mappings[IDOK] = button::ok; + m_mappings[IDYES] = button::yes; + m_mappings[IDNO] = button::no; + m_mappings[IDABORT] = button::abort; + m_mappings[IDRETRY] = button::retry; + m_mappings[IDIGNORE] = button::ignore; + + m_async->start_func([text, title, style](int* exit_code) -> std::string { + auto wtext = internal::str2wstr(text); + auto wtitle = internal::str2wstr(title); + // Apply new visual style (required for all Windows versions) + new_style_context ctx; + *exit_code = MessageBoxW(GetActiveWindow(), wtext.c_str(), wtitle.c_str(), style); + return ""; + }); + +#elif __EMSCRIPTEN__ + std::string full_message; + switch (_icon) { + case icon::warning: + full_message = "⚠️"; + break; + case icon::error: + full_message = "⛔"; + break; + case icon::question: + full_message = "❓"; + break; + /* case icon::info: */ default: + full_message = "ℹ"; + break; + } + + full_message += ' ' + title + "\n\n" + text; + + // This does not really start an async task; it just passes the + // EM_ASM_INT return value to a fake start() function. + m_async->start(EM_ASM_INT( + { + if ($1) return window.confirm(UTF8ToString($0)) ? 0 : -1; + alert(UTF8ToString($0)); + return 0; + }, + full_message.c_str(), _choice == choice::ok_cancel)); +#else + auto command = desktop_helper(); + + if (is_osascript()) { + std::string script = + "display dialog " + osascript_quote(text) + " with title " + osascript_quote(title); + auto if_cancel = button::cancel; + switch (_choice) { + case choice::ok_cancel: + script += + "buttons {\"OK\", \"Cancel\"}" + " default button \"OK\"" + " cancel button \"Cancel\""; + break; + case choice::yes_no: + script += + "buttons {\"Yes\", \"No\"}" + " default button \"Yes\"" + " cancel button \"No\""; + if_cancel = button::no; + break; + case choice::yes_no_cancel: + script += + "buttons {\"Yes\", \"No\", \"Cancel\"}" + " default button \"Yes\"" + " cancel button \"Cancel\""; + break; + case choice::retry_cancel: + script += + "buttons {\"Retry\", \"Cancel\"}" + " default button \"Retry\"" + " cancel button \"Cancel\""; + break; + case choice::abort_retry_ignore: + script += + "buttons {\"Abort\", \"Retry\", \"Ignore\"}" + " default button \"Abort\"" + " cancel button \"Retry\""; + if_cancel = button::retry; + break; + case choice::ok: + default: + script += + "buttons {\"OK\"}" + " default button \"OK\"" + " cancel button \"OK\""; + if_cancel = button::ok; + break; + } + m_mappings[1] = if_cancel; + m_mappings[256] = if_cancel; // XXX: I think this was never correct + script += " with icon "; + switch (_icon) { +#define PFD_OSX_ICON(n) \ + "alias ((path to library folder from system domain) as text " \ + "& \"CoreServices:CoreTypes.bundle:Contents:Resources:" n ".icns\")" + case icon::info: + default: + script += PFD_OSX_ICON("ToolBarInfo"); + break; + case icon::warning: + script += "caution"; + break; + case icon::error: + script += "stop"; + break; + case icon::question: + script += PFD_OSX_ICON("GenericQuestionMarkIcon"); + break; +#undef PFD_OSX_ICON + } + + command.push_back("-e"); + command.push_back(script); + } else if (is_zenity()) { + switch (_choice) { + case choice::ok_cancel: + command.insert(command.end(), {"--question", "--cancel-label=Cancel", "--ok-label=OK"}); + break; + case choice::yes_no: + // Do not use standard --question because it causes “No” to return -1, + // which is inconsistent with the “Yes/No/Cancel” mode below. + command.insert(command.end(), + {"--question", "--switch", "--extra-button=No", "--extra-button=Yes"}); + break; + case choice::yes_no_cancel: + command.insert(command.end(), {"--question", "--switch", "--extra-button=Cancel", + "--extra-button=No", "--extra-button=Yes"}); + break; + case choice::retry_cancel: + command.insert(command.end(), + {"--question", "--switch", "--extra-button=Cancel", "--extra-button=Retry"}); + break; + case choice::abort_retry_ignore: + command.insert(command.end(), {"--question", "--switch", "--extra-button=Ignore", + "--extra-button=Abort", "--extra-button=Retry"}); + break; + case choice::ok: + default: + switch (_icon) { + case icon::error: + command.push_back("--error"); + break; + case icon::warning: + command.push_back("--warning"); + break; + default: + command.push_back("--info"); + break; + } + } + + command.insert(command.end(), + {"--title", title, "--width=300", "--height=0", // sensible defaults + "--no-markup", // do not interpret text as Pango markup + "--text", text, "--icon-name=dialog-" + get_icon_name(_icon)}); + } else if (is_kdialog()) { + if (_choice == choice::ok) { + switch (_icon) { + case icon::error: + command.push_back("--error"); + break; + case icon::warning: + command.push_back("--sorry"); + break; + default: + command.push_back("--msgbox"); + break; + } + } else { + std::string flag = "--"; + if (_icon == icon::warning || _icon == icon::error) flag += "warning"; + flag += "yesno"; + if (_choice == choice::yes_no_cancel) flag += "cancel"; + command.push_back(flag); + if (_choice == choice::yes_no || _choice == choice::yes_no_cancel) { + m_mappings[0] = button::yes; + m_mappings[256] = button::no; + } + } + + command.push_back(text); + command.push_back("--title"); + command.push_back(title); + + // Must be after the above part + if (_choice == choice::ok_cancel) + command.insert(command.end(), {"--yes-label", "OK", "--no-label", "Cancel"}); + } + + if (flags(flag::is_verbose)) std::cerr << "pfd: " << command << std::endl; + + m_async->start_process(command); +#endif +} + +inline button message::result() { + int exit_code; + auto ret = m_async->result(&exit_code); + // osascript will say "button returned:Cancel\n" + // and others will just say "Cancel\n" + if (internal::ends_with(ret, "Cancel\n")) return button::cancel; + if (internal::ends_with(ret, "OK\n")) return button::ok; + if (internal::ends_with(ret, "Yes\n")) return button::yes; + if (internal::ends_with(ret, "No\n")) return button::no; + if (internal::ends_with(ret, "Abort\n")) return button::abort; + if (internal::ends_with(ret, "Retry\n")) return button::retry; + if (internal::ends_with(ret, "Ignore\n")) return button::ignore; + if (m_mappings.count(exit_code) != 0) return m_mappings[exit_code]; + return exit_code == 0 ? button::ok : button::cancel; +} + +// open_file implementation + +inline open_file::open_file(std::string const& title, std::string const& default_path /* = "" */, + std::vector<std::string> const& filters /* = { "All Files", "*" } */, + opt options /* = opt::none */) + : file_dialog(type::open, title, default_path, filters, options) {} + +inline open_file::open_file(std::string const& title, std::string const& default_path, + std::vector<std::string> const& filters, bool allow_multiselect) + : open_file(title, default_path, filters, (allow_multiselect ? opt::multiselect : opt::none)) {} + +inline std::vector<std::string> open_file::result() { + return vector_result(); +} + +// save_file implementation + +inline save_file::save_file(std::string const& title, std::string const& default_path /* = "" */, + std::vector<std::string> const& filters /* = { "All Files", "*" } */, + opt options /* = opt::none */) + : file_dialog(type::save, title, default_path, filters, options) {} + +inline save_file::save_file(std::string const& title, std::string const& default_path, + std::vector<std::string> const& filters, bool confirm_overwrite) + : save_file(title, default_path, filters, + (confirm_overwrite ? opt::none : opt::force_overwrite)) {} + +inline std::string save_file::result() { + return string_result(); +} + +// select_folder implementation + +inline select_folder::select_folder(std::string const& title, + std::string const& default_path /* = "" */, + opt options /* = opt::none */) + : file_dialog(type::folder, title, default_path, {}, options) {} + +inline std::string select_folder::result() { + return string_result(); +} + +#endif // PFD_SKIP_IMPLEMENTATION + +} // namespace pfd |
