// SPDX-License-Identifier: MIT /* $info$ meta: ir|dumper ~ IR -> Text tags: ir|dumper $end_info$ */ #include "Interface/IR/IntrusiveIRList.h" #include "Interface/IR/RegisterAllocationData.h" #include #include #include #include #include #include #include #include #include namespace FEXCore::IR { #define IROP_GETNAME_IMPL #define IROP_GETRAARGS_IMPL #define IROP_REG_CLASSES_IMPL #define IROP_HASSIDEEFFECTS_IMPL #define IROP_SIZES_IMPL #define IROP_GETHASDEST_IMPL #include static void PrintArg(fextl::ostringstream* out, const IRListView*, const SHA256Sum& Arg) { *out << fextl::fmt::format("sha256:{:02x}", fmt::join(Arg.data, "")); } static void PrintArg(fextl::ostringstream* out, const IRListView*, uint64_t Arg) { *out << fextl::fmt::format("#{:#x}", Arg); } static void PrintArg(fextl::ostringstream* out, const IRListView*, const char* const Arg) { *out << fextl::fmt::format("'{}'", Arg); } static void PrintArg(fextl::ostringstream* out, const IRListView*, CondClass Arg) { if (Arg == CondClass::AL) { *out << "ALWAYS"; return; } static constexpr std::array CondNames = {"EQ", "NEQ", "UGE", "ULT", "MI", "PL", "VS", "VC", "UGT", "ULE", "SGE", "SLT", "SGT", "SLE", "TSTZ", "TSTNZ", "FLU", "FGE", "FLEU", "FGT", "FU", "FNU"}; *out << CondNames[FEXCore::ToUnderlying(Arg)]; } static void PrintArg(fextl::ostringstream* out, const IRListView*, MemOffsetType Arg) { static constexpr std::array Names = { "SXTX", "UXTW", "SXTW", }; *out << Names[FEXCore::ToUnderlying(Arg)]; } static void PrintArg(fextl::ostringstream* out, const IRListView*, RegClass Arg) { *out << [Arg] { switch (Arg) { case RegClass::Invalid: return "Invalid"; case RegClass::GPR: return "GPR"; case RegClass::GPRFixed: return "GPRFixed"; case RegClass::FPR: return "FPR"; case RegClass::FPRFixed: return "FPRFixed"; case RegClass::Complex: return "Complex"; } return ""; }(); } static void PrintArg(fextl::ostringstream* out, const IRListView* IR, OrderedNodeWrapper Arg) { if (Arg.IsImmediate()) { auto PhyReg = PhysicalRegister(Arg); switch (PhyReg.AsRegClass()) { case RegClass::GPR: *out << "r"; break; case RegClass::GPRFixed: *out << "R"; break; case RegClass::FPR: *out << "v"; break; case RegClass::FPRFixed: *out << "V"; break; case RegClass::Complex: *out << "c"; break; case RegClass::Invalid: *out << "invalid"; break; default: *out << "unknown"; break; } if (PhyReg.AsRegClass() != RegClass::Invalid) { *out << std::dec << uint32_t(PhyReg.Reg); } return; } auto [CodeNode, IROp] = IR->at(Arg)(); const auto ArgID = Arg.ID(); if (ArgID.IsInvalid()) { *out << "%Invalid"; } else { *out << "%" << std::dec << ArgID; } if (GetHasDest(IROp->Op)) { auto ElementSize = IROp->ElementSize; uint32_t NumElements = 0; if (IROp->ElementSize == OpSize::iUnsized) { ElementSize = IROp->Size; } if (ElementSize != OpSize::iUnsized) { NumElements = IR::NumElements(IROp->Size, ElementSize); } *out << " i" << std::dec << IR::OpSizeAsBits(ElementSize); if (NumElements > 1) { *out << "v" << std::dec << NumElements; } } } static void PrintArg(fextl::ostringstream* out, const IRListView*, FenceType Arg) { *out << [Arg] { switch (Arg) { case FenceType::Load: return "Loads"; case FenceType::Store: return "Stores"; case FenceType::LoadStore: return "LoadStores"; case FenceType::Inst: return "Instruction"; } return ""; }(); } static void PrintArg(fextl::ostringstream* out, const IRListView*, RoundMode Arg) { *out << [Arg] { switch (Arg) { case RoundMode::Nearest: return "Nearest"; case RoundMode::NegInfinity: return "-Inf"; case RoundMode::PosInfinity: return "+Inf"; case RoundMode::TowardsZero: return "Towards Zero"; case RoundMode::Host: return "Host"; } return ""; }(); } static void PrintArg(fextl::ostringstream* out, const IRListView*, ConstPad Arg) { *out << [Arg] { switch (Arg) { case ConstPad::NoPad: return "NoPad"; case ConstPad::DoPad: return "DoPad"; case ConstPad::AutoPad: return "AutoPad"; } return ""; }(); } static void PrintArg(fextl::ostringstream* out, const IRListView*, NamedVectorConstant Arg) { *out << [Arg] { // clang-format off switch (Arg) { case NamedVectorConstant::NAMED_VECTOR_INCREMENTAL_U16_INDEX: return "u16_incremental_index"; case NamedVectorConstant::NAMED_VECTOR_INCREMENTAL_U16_INDEX_UPPER: return "u16_incremental_index_upper"; case NamedVectorConstant::NAMED_VECTOR_PADDSUBPS_INVERT: return "addsubps_invert"; case NamedVectorConstant::NAMED_VECTOR_PADDSUBPS_INVERT_UPPER: return "addsubps_invert_upper"; case NamedVectorConstant::NAMED_VECTOR_PADDSUBPD_INVERT: return "addsubpd_invert"; case NamedVectorConstant::NAMED_VECTOR_PADDSUBPD_INVERT_UPPER: return "addsubpd_invert_upper"; case NamedVectorConstant::NAMED_VECTOR_PSUBADDPS_INVERT: return "subaddps_invert"; case NamedVectorConstant::NAMED_VECTOR_PSUBADDPS_INVERT_UPPER: return "subaddps_invert_upper"; case NamedVectorConstant::NAMED_VECTOR_PSUBADDPD_INVERT: return "subaddpd_invert"; case NamedVectorConstant::NAMED_VECTOR_PSUBADDPD_INVERT_UPPER: return "subaddpd_invert_upper"; case NamedVectorConstant::NAMED_VECTOR_MOVMSKPS_SHIFT: return "movmskps_shift"; case NamedVectorConstant::NAMED_VECTOR_AESKEYGENASSIST_SWIZZLE: return "aeskeygenassist_swizzle"; case NamedVectorConstant::NAMED_VECTOR_BLENDPS_0110B: return "blendps_0110b"; case NamedVectorConstant::NAMED_VECTOR_BLENDPS_0111B: return "blendps_0111b"; case NamedVectorConstant::NAMED_VECTOR_BLENDPS_1001B: return "blendps_1001b"; case NamedVectorConstant::NAMED_VECTOR_BLENDPS_1011B: return "blendps_1011b"; case NamedVectorConstant::NAMED_VECTOR_BLENDPS_1101B: return "blendps_1101b"; case NamedVectorConstant::NAMED_VECTOR_BLENDPS_1110B: return "blendps_1110b"; case NamedVectorConstant::NAMED_VECTOR_MOVMASKB: return "movmaskb"; case NamedVectorConstant::NAMED_VECTOR_MOVMASKB_UPPER: return "movmaskb_upper"; case NamedVectorConstant::NAMED_VECTOR_256_MID_ELEMENT_SWAP: return "v256_mid_element_swap"; case NamedVectorConstant::NAMED_VECTOR_256_MID_ELEMENT_SWAP_UPPER: return "v256_mid_element_swap_upper"; case NamedVectorConstant::NAMED_VECTOR_ZERO: return "vectorzero"; case NamedVectorConstant::NAMED_VECTOR_X87_ONE: return "x87_1_0"; case NamedVectorConstant::NAMED_VECTOR_X87_LOG2_10: return "x87_log2_10"; case NamedVectorConstant::NAMED_VECTOR_X87_LOG2_E: return "x87_log2_e"; case NamedVectorConstant::NAMED_VECTOR_X87_PI: return "x87_pi"; case NamedVectorConstant::NAMED_VECTOR_X87_LOG10_2: return "x87_log10_2"; case NamedVectorConstant::NAMED_VECTOR_X87_LOG_2: return "x87_log2"; case NamedVectorConstant::NAMED_VECTOR_CVTMAX_F32_I32: return "cvtmax_f32_i32"; case NamedVectorConstant::NAMED_VECTOR_CVTMAX_F32_I32_UPPER: return "cvtmax_f32_i32_upper"; case NamedVectorConstant::NAMED_VECTOR_CVTMAX_F32_I64: return "cvtmax_f32_i64"; case NamedVectorConstant::NAMED_VECTOR_CVTMAX_F64_I32: return "cvtmax_f64_i32"; case NamedVectorConstant::NAMED_VECTOR_CVTMAX_F64_I32_UPPER: return "cvtmax_f64_i32_upper"; case NamedVectorConstant::NAMED_VECTOR_CVTMAX_F64_I64: return "cvtmax_f64_i64"; case NamedVectorConstant::NAMED_VECTOR_CVTMAX_I32: return "cvtmax_i32"; case NamedVectorConstant::NAMED_VECTOR_CVTMAX_I64: return "cvtmax_i64"; case NamedVectorConstant::NAMED_VECTOR_F80_SIGN_MASK: return "f80_sign_mask"; case NamedVectorConstant::NAMED_VECTOR_SHA1RNDS_K0: return "sha1rnds_k0"; case NamedVectorConstant::NAMED_VECTOR_SHA1RNDS_K1: return "sha1rnds_k1"; case NamedVectorConstant::NAMED_VECTOR_SHA1RNDS_K2: return "sha1rnds_k2"; case NamedVectorConstant::NAMED_VECTOR_SHA1RNDS_K3: return "sha1rnds_k3"; case NamedVectorConstant::NAMED_VECTOR_MAX: return ""; } return ""; // clang-format on }(); } static void PrintArg(fextl::ostringstream* out, const IRListView*, IndexNamedVectorConstant Arg) { *out << [Arg] { // clang-format off switch (Arg) { case IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_PSHUFLW: return "pshuflw"; case IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_PSHUFHW: return "pshufhw"; case IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_PSHUFD: return "pshufd"; case IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_SHUFPS: return "shufps"; case IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_DPPS_MASK: return "dpps_mask"; case IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_DPPD_MASK: return "dppd_mask"; case IndexNamedVectorConstant::INDEXED_NAMED_VECTOR_PBLENDW: return "pblendw"; case INDEXED_NAMED_VECTOR_MAX: return ""; } return ""; // clang-format on }(); } static void PrintArg(fextl::ostringstream* out, const IRListView*, OpSize Arg) { *out << [Arg] { switch (Arg) { case OpSize::iUnsized: return "Unsized"; case OpSize::i8Bit: return "i8"; case OpSize::i16Bit: return "i16"; case OpSize::i32Bit: return "i32"; case OpSize::i64Bit: return "i64"; case OpSize::f80Bit: return "f80"; case OpSize::i128Bit: return "i128"; case OpSize::i256Bit: return "i256"; case OpSize::iInvalid: return "Invalid"; } return ""; }(); } static void PrintArg(fextl::ostringstream* out, const IRListView*, FloatCompareOp Arg) { *out << [Arg] { switch (Arg) { case FloatCompareOp::EQ: return "FEQ"; case FloatCompareOp::LT: return "FLT"; case FloatCompareOp::LE: return "FLE"; case FloatCompareOp::UNO: return "UNO"; case FloatCompareOp::NEQ: return "NEQ"; case FloatCompareOp::ORD: return "ORD"; } return ""; }(); } static void PrintArg(fextl::ostringstream* out, const IRListView*, FEXCore::IR::BreakDefinition Arg) { *out << "{" << Arg.ErrorRegister << "."; *out << static_cast(Arg.Signal) << "."; *out << static_cast(Arg.TrapNumber) << "."; *out << static_cast(Arg.si_code) << "}"; } static void PrintArg(fextl::ostringstream* out, const IRListView*, ShiftType Arg) { *out << [Arg] { switch (Arg) { case ShiftType::LSL: return "LSL"; case ShiftType::LSR: return "LSR"; case ShiftType::ASR: return "ASR"; case ShiftType::ROR: return "ROR"; } return ""; }(); } static void PrintArg(fextl::ostringstream* out, const IRListView*, BranchHint Arg) { *out << [Arg] { switch (Arg) { case BranchHint::None: return "None"; case BranchHint::Call: return "Call"; case BranchHint::Return: return "Return"; case BranchHint::CheckTF: return "CheckTF"; } return ""; }(); } static void PrintArg(fextl::ostringstream* out, const IRListView*, const std::array& Arg) { *out << fextl::fmt::format("{:02x}", fmt::join(Arg, "")); } void Dump(fextl::ostringstream* out, const IRListView* IR) { auto HeaderOp = IR->GetHeader(); int8_t CurrentIndent = 0; auto AddIndent = [&out, &CurrentIndent]() { for (uint8_t i = 0; i < CurrentIndent; ++i) { *out << "\t"; } }; ++CurrentIndent; AddIndent(); *out << fextl::fmt::format("(%0) IRHeader %{}, #{:#x}, #{}, #{}\n", HeaderOp->Blocks.ID(), +HeaderOp->OriginalRIP, +HeaderOp->BlockCount, +HeaderOp->NumHostInstructions); for (auto [BlockNode, BlockHeader] : IR->GetBlocks()) { { auto BlockIROp = BlockHeader->C(); AddIndent(); *out << "(%" << IR->GetID(BlockNode) << ") " << "CodeBlock "; *out << "%" << BlockIROp->Begin.ID() << ", "; *out << "%" << BlockIROp->Last.ID() << std::endl; } ++CurrentIndent; for (auto [CodeNode, IROp] : IR->GetCode(BlockNode)) { const auto ID = IR->GetID(CodeNode); const auto Name = FEXCore::IR::GetName(IROp->Op); { AddIndent(); if (GetHasDest(IROp->Op)) { auto ElementSize = IROp->ElementSize; uint8_t NumElements = 0; if (IROp->ElementSize != OpSize::iUnsized) { ElementSize = IROp->Size; } if (ElementSize != OpSize::iUnsized) { NumElements = IR::NumElements(IROp->Size, ElementSize); } *out << "%" << std::dec << ID; auto PhyReg = PhysicalRegister(CodeNode); if (!PhyReg.IsInvalid()) { switch (PhyReg.AsRegClass()) { case RegClass::GPR: *out << "(r"; break; case RegClass::GPRFixed: *out << "(R"; break; case RegClass::FPR: *out << "(v"; break; case RegClass::FPRFixed: *out << "(V"; break; case RegClass::Complex: *out << "(complex"; break; case RegClass::Invalid: *out << "(invalid"; break; default: *out << "(unknown"; break; } if (PhyReg.AsRegClass() != RegClass::Invalid) { *out << std::dec << uint32_t(PhyReg.Reg) << ")"; } else { *out << ")"; } } *out << " i" << std::dec << IR::OpSizeAsBits(ElementSize); if (NumElements > 1) { *out << "v" << std::dec << NumElements; } *out << " = "; } else { auto ElementSize = IROp->ElementSize; if (IROp->ElementSize == OpSize::iUnsized) { ElementSize = IROp->Size; } uint32_t NumElements = 0; if (ElementSize != OpSize::iUnsized) { NumElements = IR::NumElements(IROp->Size, ElementSize); } *out << "(%" << std::dec << ID << ' '; *out << 'i' << std::dec << IR::OpSizeAsBits(ElementSize); if (NumElements > 1) { *out << 'v' << std::dec << NumElements; } *out << ") "; } *out << Name; #define IROP_ARGPRINTER_HELPER #include default: *out << ""; break; } //*out << " (" << std::dec << CodeNode->GetUses() << ")"; *out << "\n"; } } CurrentIndent = std::max(0, CurrentIndent - 1); } } }