//===- SelectionDAGDumper.cpp - Implement SelectionDAG::dump() ------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This implements the SelectionDAG::dump method and friends. // //===----------------------------------------------------------------------===// #include "SDNodeDbgValue.h" #include "llvm/ADT/APFloat.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringExtras.h" #include "llvm/CodeGen/ISDOpcodes.h" #include "llvm/CodeGen/MachineBasicBlock.h" #include "llvm/CodeGen/MachineConstantPool.h" #include "llvm/CodeGen/MachineMemOperand.h" #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/CodeGen/SelectionDAGNodes.h" #include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/CodeGen/TargetLowering.h" #include "llvm/CodeGen/TargetRegisterInfo.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/CodeGen/ValueTypes.h" #include "llvm/Config/llvm-config.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DebugLoc.h" #include "llvm/IR/Function.h" #include "llvm/IR/Intrinsics.h" #include "llvm/IR/ModuleSlotTracker.h" #include "llvm/IR/Value.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MachineValueType.h" #include "llvm/Support/Printable.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetIntrinsicInfo.h" #include "llvm/Target/TargetMachine.h" #include #include using namespace llvm; static cl::opt VerboseDAGDumping("dag-dump-verbose", cl::Hidden, cl::desc("Display more information when dumping selection " "DAG nodes.")); std::string SDNode::getOperationName(const SelectionDAG *G) const { switch (getOpcode()) { default: if (getOpcode() < ISD::BUILTIN_OP_END) return "<>"; if (isMachineOpcode()) { if (G) if (const TargetInstrInfo *TII = G->getSubtarget().getInstrInfo()) if (getMachineOpcode() < TII->getNumOpcodes()) return std::string(TII->getName(getMachineOpcode())); return "<>"; } if (G) { const TargetLowering &TLI = G->getTargetLoweringInfo(); const char *Name = TLI.getTargetNodeName(getOpcode()); if (Name) return Name; return "<>"; } return "<>"; #ifndef NDEBUG case ISD::DELETED_NODE: return "<>"; #endif case ISD::PREFETCH: return "Prefetch"; case ISD::MEMBARRIER: return "MemBarrier"; case ISD::ATOMIC_FENCE: return "AtomicFence"; case ISD::ATOMIC_CMP_SWAP: return "AtomicCmpSwap"; case ISD::ATOMIC_CMP_SWAP_WITH_SUCCESS: return "AtomicCmpSwapWithSuccess"; case ISD::ATOMIC_SWAP: return "AtomicSwap"; case ISD::ATOMIC_LOAD_ADD: return "AtomicLoadAdd"; case ISD::ATOMIC_LOAD_SUB: return "AtomicLoadSub"; case ISD::ATOMIC_LOAD_AND: return "AtomicLoadAnd"; case ISD::ATOMIC_LOAD_CLR: return "AtomicLoadClr"; case ISD::ATOMIC_LOAD_OR: return "AtomicLoadOr"; case ISD::ATOMIC_LOAD_XOR: return "AtomicLoadXor"; case ISD::ATOMIC_LOAD_NAND: return "AtomicLoadNand"; case ISD::ATOMIC_LOAD_MIN: return "AtomicLoadMin"; case ISD::ATOMIC_LOAD_MAX: return "AtomicLoadMax"; case ISD::ATOMIC_LOAD_UMIN: return "AtomicLoadUMin"; case ISD::ATOMIC_LOAD_UMAX: return "AtomicLoadUMax"; case ISD::ATOMIC_LOAD_FADD: return "AtomicLoadFAdd"; case ISD::ATOMIC_LOAD_UINC_WRAP: return "AtomicLoadUIncWrap"; case ISD::ATOMIC_LOAD_UDEC_WRAP: return "AtomicLoadUDecWrap"; case ISD::ATOMIC_LOAD: return "AtomicLoad"; case ISD::ATOMIC_STORE: return "AtomicStore"; case ISD::PCMARKER: return "PCMarker"; case ISD::READCYCLECOUNTER: return "ReadCycleCounter"; case ISD::SRCVALUE: return "SrcValue"; case ISD::MDNODE_SDNODE: return "MDNode"; case ISD::EntryToken: return "EntryToken"; case ISD::TokenFactor: return "TokenFactor"; case ISD::AssertSext: return "AssertSext"; case ISD::AssertZext: return "AssertZext"; case ISD::AssertAlign: return "AssertAlign"; case ISD::BasicBlock: return "BasicBlock"; case ISD::VALUETYPE: return "ValueType"; case ISD::Register: return "Register"; case ISD::RegisterMask: return "RegisterMask"; case ISD::Constant: if (cast(this)->isOpaque()) return "OpaqueConstant"; return "Constant"; case ISD::ConstantFP: return "ConstantFP"; case ISD::GlobalAddress: return "GlobalAddress"; case ISD::GlobalTLSAddress: return "GlobalTLSAddress"; case ISD::FrameIndex: return "FrameIndex"; case ISD::JumpTable: return "JumpTable"; case ISD::GLOBAL_OFFSET_TABLE: return "GLOBAL_OFFSET_TABLE"; case ISD::RETURNADDR: return "RETURNADDR"; case ISD::ADDROFRETURNADDR: return "ADDROFRETURNADDR"; case ISD::FRAMEADDR: return "FRAMEADDR"; case ISD::SPONENTRY: return "SPONENTRY"; case ISD::LOCAL_RECOVER: return "LOCAL_RECOVER"; case ISD::READ_REGISTER: return "READ_REGISTER"; case ISD::WRITE_REGISTER: return "WRITE_REGISTER"; case ISD::FRAME_TO_ARGS_OFFSET: return "FRAME_TO_ARGS_OFFSET"; case ISD::EH_DWARF_CFA: return "EH_DWARF_CFA"; case ISD::EH_RETURN: return "EH_RETURN"; case ISD::EH_SJLJ_SETJMP: return "EH_SJLJ_SETJMP"; case ISD::EH_SJLJ_LONGJMP: return "EH_SJLJ_LONGJMP"; case ISD::EH_SJLJ_SETUP_DISPATCH: return "EH_SJLJ_SETUP_DISPATCH"; case ISD::ConstantPool: return "ConstantPool"; case ISD::TargetIndex: return "TargetIndex"; case ISD::ExternalSymbol: return "ExternalSymbol"; case ISD::BlockAddress: return "BlockAddress"; case ISD::INTRINSIC_WO_CHAIN: case ISD::INTRINSIC_VOID: case ISD::INTRINSIC_W_CHAIN: { unsigned OpNo = getOpcode() == ISD::INTRINSIC_WO_CHAIN ? 0 : 1; unsigned IID = cast(getOperand(OpNo))->getZExtValue(); if (IID < Intrinsic::num_intrinsics) return Intrinsic::getBaseName((Intrinsic::ID)IID).str(); if (!G) return "Unknown intrinsic"; if (const TargetIntrinsicInfo *TII = G->getTarget().getIntrinsicInfo()) return TII->getName(IID); llvm_unreachable("Invalid intrinsic ID"); } case ISD::BUILD_VECTOR: return "BUILD_VECTOR"; case ISD::TargetConstant: if (cast(this)->isOpaque()) return "OpaqueTargetConstant"; return "TargetConstant"; case ISD::TargetConstantFP: return "TargetConstantFP"; case ISD::TargetGlobalAddress: return "TargetGlobalAddress"; case ISD::TargetGlobalTLSAddress: return "TargetGlobalTLSAddress"; case ISD::TargetFrameIndex: return "TargetFrameIndex"; case ISD::TargetJumpTable: return "TargetJumpTable"; case ISD::TargetConstantPool: return "TargetConstantPool"; case ISD::TargetExternalSymbol: return "TargetExternalSymbol"; case ISD::MCSymbol: return "MCSymbol"; case ISD::TargetBlockAddress: return "TargetBlockAddress"; case ISD::CopyToReg: return "CopyToReg"; case ISD::CopyFromReg: return "CopyFromReg"; case ISD::UNDEF: return "undef"; case ISD::VSCALE: return "vscale"; case ISD::MERGE_VALUES: return "merge_values"; case ISD::INLINEASM: return "inlineasm"; case ISD::INLINEASM_BR: return "inlineasm_br"; case ISD::EH_LABEL: return "eh_label"; case ISD::ANNOTATION_LABEL: return "annotation_label"; case ISD::HANDLENODE: return "handlenode"; // Unary operators case ISD::FABS: return "fabs"; case ISD::FMINNUM: return "fminnum"; case ISD::STRICT_FMINNUM: return "strict_fminnum"; case ISD::FMAXNUM: return "fmaxnum"; case ISD::STRICT_FMAXNUM: return "strict_fmaxnum"; case ISD::FMINNUM_IEEE: return "fminnum_ieee"; case ISD::FMAXNUM_IEEE: return "fmaxnum_ieee"; case ISD::FMINIMUM: return "fminimum"; case ISD::STRICT_FMINIMUM: return "strict_fminimum"; case ISD::FMAXIMUM: return "fmaximum"; case ISD::STRICT_FMAXIMUM: return "strict_fmaximum"; case ISD::FNEG: return "fneg"; case ISD::FSQRT: return "fsqrt"; case ISD::STRICT_FSQRT: return "strict_fsqrt"; case ISD::FCBRT: return "fcbrt"; case ISD::FSIN: return "fsin"; case ISD::STRICT_FSIN: return "strict_fsin"; case ISD::FCOS: return "fcos"; case ISD::STRICT_FCOS: return "strict_fcos"; case ISD::FSINCOS: return "fsincos"; case ISD::FTRUNC: return "ftrunc"; case ISD::STRICT_FTRUNC: return "strict_ftrunc"; case ISD::FFLOOR: return "ffloor"; case ISD::STRICT_FFLOOR: return "strict_ffloor"; case ISD::FCEIL: return "fceil"; case ISD::STRICT_FCEIL: return "strict_fceil"; case ISD::FRINT: return "frint"; case ISD::STRICT_FRINT: return "strict_frint"; case ISD::FNEARBYINT: return "fnearbyint"; case ISD::STRICT_FNEARBYINT: return "strict_fnearbyint"; case ISD::FROUND: return "fround"; case ISD::STRICT_FROUND: return "strict_fround"; case ISD::FROUNDEVEN: return "froundeven"; case ISD::STRICT_FROUNDEVEN: return "strict_froundeven"; case ISD::FEXP: return "fexp"; case ISD::STRICT_FEXP: return "strict_fexp"; case ISD::FEXP2: return "fexp2"; case ISD::STRICT_FEXP2: return "strict_fexp2"; case ISD::FLOG: return "flog"; case ISD::STRICT_FLOG: return "strict_flog"; case ISD::FLOG2: return "flog2"; case ISD::STRICT_FLOG2: return "strict_flog2"; case ISD::FLOG10: return "flog10"; case ISD::STRICT_FLOG10: return "strict_flog10"; // Binary operators case ISD::ADD: return "add"; case ISD::SUB: return "sub"; case ISD::MUL: return "mul"; case ISD::MULHU: return "mulhu"; case ISD::MULHS: return "mulhs"; case ISD::AVGFLOORU: return "avgflooru"; case ISD::AVGFLOORS: return "avgfloors"; case ISD::AVGCEILU: return "avgceilu"; case ISD::AVGCEILS: return "avgceils"; case ISD::ABDS: return "abds"; case ISD::ABDU: return "abdu"; case ISD::SDIV: return "sdiv"; case ISD::UDIV: return "udiv"; case ISD::SREM: return "srem"; case ISD::UREM: return "urem"; case ISD::SMUL_LOHI: return "smul_lohi"; case ISD::UMUL_LOHI: return "umul_lohi"; case ISD::SDIVREM: return "sdivrem"; case ISD::UDIVREM: return "udivrem"; case ISD::AND: return "and"; case ISD::OR: return "or"; case ISD::XOR: return "xor"; case ISD::SHL: return "shl"; case ISD::SRA: return "sra"; case ISD::SRL: return "srl"; case ISD::ROTL: return "rotl"; case ISD::ROTR: return "rotr"; case ISD::FSHL: return "fshl"; case ISD::FSHR: return "fshr"; case ISD::FADD: return "fadd"; case ISD::STRICT_FADD: return "strict_fadd"; case ISD::FSUB: return "fsub"; case ISD::STRICT_FSUB: return "strict_fsub"; case ISD::FMUL: return "fmul"; case ISD::STRICT_FMUL: return "strict_fmul"; case ISD::FDIV: return "fdiv"; case ISD::STRICT_FDIV: return "strict_fdiv"; case ISD::FMA: return "fma"; case ISD::STRICT_FMA: return "strict_fma"; case ISD::FMAD: return "fmad"; case ISD::FREM: return "frem"; case ISD::STRICT_FREM: return "strict_frem"; case ISD::FCOPYSIGN: return "fcopysign"; case ISD::FGETSIGN: return "fgetsign"; case ISD::FCANONICALIZE: return "fcanonicalize"; case ISD::IS_FPCLASS: return "is_fpclass"; case ISD::FPOW: return "fpow"; case ISD::STRICT_FPOW: return "strict_fpow"; case ISD::SMIN: return "smin"; case ISD::SMAX: return "smax"; case ISD::UMIN: return "umin"; case ISD::UMAX: return "umax"; case ISD::FPOWI: return "fpowi"; case ISD::STRICT_FPOWI: return "strict_fpowi"; case ISD::SETCC: return "setcc"; case ISD::SETCCCARRY: return "setcccarry"; case ISD::STRICT_FSETCC: return "strict_fsetcc"; case ISD::STRICT_FSETCCS: return "strict_fsetccs"; case ISD::SELECT: return "select"; case ISD::VSELECT: return "vselect"; case ISD::SELECT_CC: return "select_cc"; case ISD::INSERT_VECTOR_ELT: return "insert_vector_elt"; case ISD::EXTRACT_VECTOR_ELT: return "extract_vector_elt"; case ISD::CONCAT_VECTORS: return "concat_vectors"; case ISD::INSERT_SUBVECTOR: return "insert_subvector"; case ISD::EXTRACT_SUBVECTOR: return "extract_subvector"; case ISD::SCALAR_TO_VECTOR: return "scalar_to_vector"; case ISD::VECTOR_SHUFFLE: return "vector_shuffle"; case ISD::VECTOR_SPLICE: return "vector_splice"; case ISD::SPLAT_VECTOR: return "splat_vector"; case ISD::SPLAT_VECTOR_PARTS: return "splat_vector_parts"; case ISD::VECTOR_REVERSE: return "vector_reverse"; case ISD::STEP_VECTOR: return "step_vector"; case ISD::CARRY_FALSE: return "carry_false"; case ISD::ADDC: return "addc"; case ISD::ADDE: return "adde"; case ISD::ADDCARRY: return "addcarry"; case ISD::SADDO_CARRY: return "saddo_carry"; case ISD::SADDO: return "saddo"; case ISD::UADDO: return "uaddo"; case ISD::SSUBO: return "ssubo"; case ISD::USUBO: return "usubo"; case ISD::SMULO: return "smulo"; case ISD::UMULO: return "umulo"; case ISD::SUBC: return "subc"; case ISD::SUBE: return "sube"; case ISD::SUBCARRY: return "subcarry"; case ISD::SSUBO_CARRY: return "ssubo_carry"; case ISD::SHL_PARTS: return "shl_parts"; case ISD::SRA_PARTS: return "sra_parts"; case ISD::SRL_PARTS: return "srl_parts"; case ISD::SADDSAT: return "saddsat"; case ISD::UADDSAT: return "uaddsat"; case ISD::SSUBSAT: return "ssubsat"; case ISD::USUBSAT: return "usubsat"; case ISD::SSHLSAT: return "sshlsat"; case ISD::USHLSAT: return "ushlsat"; case ISD::SMULFIX: return "smulfix"; case ISD::SMULFIXSAT: return "smulfixsat"; case ISD::UMULFIX: return "umulfix"; case ISD::UMULFIXSAT: return "umulfixsat"; case ISD::SDIVFIX: return "sdivfix"; case ISD::SDIVFIXSAT: return "sdivfixsat"; case ISD::UDIVFIX: return "udivfix"; case ISD::UDIVFIXSAT: return "udivfixsat"; // Conversion operators. case ISD::SIGN_EXTEND: return "sign_extend"; case ISD::ZERO_EXTEND: return "zero_extend"; case ISD::ANY_EXTEND: return "any_extend"; case ISD::SIGN_EXTEND_INREG: return "sign_extend_inreg"; case ISD::ANY_EXTEND_VECTOR_INREG: return "any_extend_vector_inreg"; case ISD::SIGN_EXTEND_VECTOR_INREG: return "sign_extend_vector_inreg"; case ISD::ZERO_EXTEND_VECTOR_INREG: return "zero_extend_vector_inreg"; case ISD::TRUNCATE: return "truncate"; case ISD::FP_ROUND: return "fp_round"; case ISD::STRICT_FP_ROUND: return "strict_fp_round"; case ISD::FP_EXTEND: return "fp_extend"; case ISD::STRICT_FP_EXTEND: return "strict_fp_extend"; case ISD::SINT_TO_FP: return "sint_to_fp"; case ISD::STRICT_SINT_TO_FP: return "strict_sint_to_fp"; case ISD::UINT_TO_FP: return "uint_to_fp"; case ISD::STRICT_UINT_TO_FP: return "strict_uint_to_fp"; case ISD::FP_TO_SINT: return "fp_to_sint"; case ISD::STRICT_FP_TO_SINT: return "strict_fp_to_sint"; case ISD::FP_TO_UINT: return "fp_to_uint"; case ISD::STRICT_FP_TO_UINT: return "strict_fp_to_uint"; case ISD::FP_TO_SINT_SAT: return "fp_to_sint_sat"; case ISD::FP_TO_UINT_SAT: return "fp_to_uint_sat"; case ISD::BITCAST: return "bitcast"; case ISD::ADDRSPACECAST: return "addrspacecast"; case ISD::FP16_TO_FP: return "fp16_to_fp"; case ISD::STRICT_FP16_TO_FP: return "strict_fp16_to_fp"; case ISD::FP_TO_FP16: return "fp_to_fp16"; case ISD::STRICT_FP_TO_FP16: return "strict_fp_to_fp16"; case ISD::BF16_TO_FP: return "bf16_to_fp"; case ISD::FP_TO_BF16: return "fp_to_bf16"; case ISD::LROUND: return "lround"; case ISD::STRICT_LROUND: return "strict_lround"; case ISD::LLROUND: return "llround"; case ISD::STRICT_LLROUND: return "strict_llround"; case ISD::LRINT: return "lrint"; case ISD::STRICT_LRINT: return "strict_lrint"; case ISD::LLRINT: return "llrint"; case ISD::STRICT_LLRINT: return "strict_llrint"; // Control flow instructions case ISD::BR: return "br"; case ISD::BRIND: return "brind"; case ISD::BR_JT: return "br_jt"; case ISD::BRCOND: return "brcond"; case ISD::BR_CC: return "br_cc"; case ISD::CALLSEQ_START: return "callseq_start"; case ISD::CALLSEQ_END: return "callseq_end"; // EH instructions case ISD::CATCHRET: return "catchret"; case ISD::CLEANUPRET: return "cleanupret"; // Other operators case ISD::LOAD: return "load"; case ISD::STORE: return "store"; case ISD::MLOAD: return "masked_load"; case ISD::MSTORE: return "masked_store"; case ISD::MGATHER: return "masked_gather"; case ISD::MSCATTER: return "masked_scatter"; case ISD::VAARG: return "vaarg"; case ISD::VACOPY: return "vacopy"; case ISD::VAEND: return "vaend"; case ISD::VASTART: return "vastart"; case ISD::DYNAMIC_STACKALLOC: return "dynamic_stackalloc"; case ISD::EXTRACT_ELEMENT: return "extract_element"; case ISD::BUILD_PAIR: return "build_pair"; case ISD::STACKSAVE: return "stacksave"; case ISD::STACKRESTORE: return "stackrestore"; case ISD::TRAP: return "trap"; case ISD::DEBUGTRAP: return "debugtrap"; case ISD::UBSANTRAP: return "ubsantrap"; case ISD::LIFETIME_START: return "lifetime.start"; case ISD::LIFETIME_END: return "lifetime.end"; case ISD::PSEUDO_PROBE: return "pseudoprobe"; case ISD::GC_TRANSITION_START: return "gc_transition.start"; case ISD::GC_TRANSITION_END: return "gc_transition.end"; case ISD::GET_DYNAMIC_AREA_OFFSET: return "get.dynamic.area.offset"; case ISD::FREEZE: return "freeze"; case ISD::PREALLOCATED_SETUP: return "call_setup"; case ISD::PREALLOCATED_ARG: return "call_alloc"; // Floating point environment manipulation case ISD::GET_ROUNDING: return "get_rounding"; case ISD::SET_ROUNDING: return "set_rounding"; // Bit manipulation case ISD::ABS: return "abs"; case ISD::BITREVERSE: return "bitreverse"; case ISD::BSWAP: return "bswap"; case ISD::CTPOP: return "ctpop"; case ISD::CTTZ: return "cttz"; case ISD::CTTZ_ZERO_UNDEF: return "cttz_zero_undef"; case ISD::CTLZ: return "ctlz"; case ISD::CTLZ_ZERO_UNDEF: return "ctlz_zero_undef"; case ISD::PARITY: return "parity"; // Trampolines case ISD::INIT_TRAMPOLINE: return "init_trampoline"; case ISD::ADJUST_TRAMPOLINE: return "adjust_trampoline"; case ISD::CONDCODE: switch (cast(this)->get()) { default: llvm_unreachable("Unknown setcc condition!"); case ISD::SETOEQ: return "setoeq"; case ISD::SETOGT: return "setogt"; case ISD::SETOGE: return "setoge"; case ISD::SETOLT: return "setolt"; case ISD::SETOLE: return "setole"; case ISD::SETONE: return "setone"; case ISD::SETO: return "seto"; case ISD::SETUO: return "setuo"; case ISD::SETUEQ: return "setueq"; case ISD::SETUGT: return "setugt"; case ISD::SETUGE: return "setuge"; case ISD::SETULT: return "setult"; case ISD::SETULE: return "setule"; case ISD::SETUNE: return "setune"; case ISD::SETEQ: return "seteq"; case ISD::SETGT: return "setgt"; case ISD::SETGE: return "setge"; case ISD::SETLT: return "setlt"; case ISD::SETLE: return "setle"; case ISD::SETNE: return "setne"; case ISD::SETTRUE: return "settrue"; case ISD::SETTRUE2: return "settrue2"; case ISD::SETFALSE: return "setfalse"; case ISD::SETFALSE2: return "setfalse2"; } case ISD::VECREDUCE_FADD: return "vecreduce_fadd"; case ISD::VECREDUCE_SEQ_FADD: return "vecreduce_seq_fadd"; case ISD::VECREDUCE_FMUL: return "vecreduce_fmul"; case ISD::VECREDUCE_SEQ_FMUL: return "vecreduce_seq_fmul"; case ISD::VECREDUCE_ADD: return "vecreduce_add"; case ISD::VECREDUCE_MUL: return "vecreduce_mul"; case ISD::VECREDUCE_AND: return "vecreduce_and"; case ISD::VECREDUCE_OR: return "vecreduce_or"; case ISD::VECREDUCE_XOR: return "vecreduce_xor"; case ISD::VECREDUCE_SMAX: return "vecreduce_smax"; case ISD::VECREDUCE_SMIN: return "vecreduce_smin"; case ISD::VECREDUCE_UMAX: return "vecreduce_umax"; case ISD::VECREDUCE_UMIN: return "vecreduce_umin"; case ISD::VECREDUCE_FMAX: return "vecreduce_fmax"; case ISD::VECREDUCE_FMIN: return "vecreduce_fmin"; case ISD::STACKMAP: return "stackmap"; case ISD::PATCHPOINT: return "patchpoint"; // Vector Predication #define BEGIN_REGISTER_VP_SDNODE(SDID, LEGALARG, NAME, ...) \ case ISD::SDID: \ return #NAME; #include "llvm/IR/VPIntrinsics.def" } } const char *SDNode::getIndexedModeName(ISD::MemIndexedMode AM) { switch (AM) { default: return ""; case ISD::PRE_INC: return ""; case ISD::PRE_DEC: return ""; case ISD::POST_INC: return ""; case ISD::POST_DEC: return ""; } } static Printable PrintNodeId(const SDNode &Node) { return Printable([&Node](raw_ostream &OS) { #ifndef NDEBUG OS << 't' << Node.PersistentId; #else OS << (const void*)&Node; #endif }); } // Print the MMO with more information from the SelectionDAG. static void printMemOperand(raw_ostream &OS, const MachineMemOperand &MMO, const MachineFunction *MF, const Module *M, const MachineFrameInfo *MFI, const TargetInstrInfo *TII, LLVMContext &Ctx) { ModuleSlotTracker MST(M); if (MF) MST.incorporateFunction(MF->getFunction()); SmallVector SSNs; MMO.print(OS, MST, SSNs, Ctx, MFI, TII); } static void printMemOperand(raw_ostream &OS, const MachineMemOperand &MMO, const SelectionDAG *G) { if (G) { const MachineFunction *MF = &G->getMachineFunction(); return printMemOperand(OS, MMO, MF, MF->getFunction().getParent(), &MF->getFrameInfo(), G->getSubtarget().getInstrInfo(), *G->getContext()); } LLVMContext Ctx; return printMemOperand(OS, MMO, /*MF=*/nullptr, /*M=*/nullptr, /*MFI=*/nullptr, /*TII=*/nullptr, Ctx); } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void SDNode::dump() const { dump(nullptr); } LLVM_DUMP_METHOD void SDNode::dump(const SelectionDAG *G) const { print(dbgs(), G); dbgs() << '\n'; } #endif void SDNode::print_types(raw_ostream &OS, const SelectionDAG *G) const { for (unsigned i = 0, e = getNumValues(); i != e; ++i) { if (i) OS << ","; if (getValueType(i) == MVT::Other) OS << "ch"; else OS << getValueType(i).getEVTString(); } } void SDNode::print_details(raw_ostream &OS, const SelectionDAG *G) const { if (getFlags().hasNoUnsignedWrap()) OS << " nuw"; if (getFlags().hasNoSignedWrap()) OS << " nsw"; if (getFlags().hasExact()) OS << " exact"; if (getFlags().hasNoNaNs()) OS << " nnan"; if (getFlags().hasNoInfs()) OS << " ninf"; if (getFlags().hasNoSignedZeros()) OS << " nsz"; if (getFlags().hasAllowReciprocal()) OS << " arcp"; if (getFlags().hasAllowContract()) OS << " contract"; if (getFlags().hasApproximateFuncs()) OS << " afn"; if (getFlags().hasAllowReassociation()) OS << " reassoc"; if (getFlags().hasNoFPExcept()) OS << " nofpexcept"; if (const MachineSDNode *MN = dyn_cast(this)) { if (!MN->memoperands_empty()) { OS << "<"; OS << "Mem:"; for (MachineSDNode::mmo_iterator i = MN->memoperands_begin(), e = MN->memoperands_end(); i != e; ++i) { printMemOperand(OS, **i, G); if (std::next(i) != e) OS << " "; } OS << ">"; } } else if (const ShuffleVectorSDNode *SVN = dyn_cast(this)) { OS << "<"; for (unsigned i = 0, e = ValueList[0].getVectorNumElements(); i != e; ++i) { int Idx = SVN->getMaskElt(i); if (i) OS << ","; if (Idx < 0) OS << "u"; else OS << Idx; } OS << ">"; } else if (const ConstantSDNode *CSDN = dyn_cast(this)) { OS << '<' << CSDN->getAPIntValue() << '>'; } else if (const ConstantFPSDNode *CSDN = dyn_cast(this)) { if (&CSDN->getValueAPF().getSemantics() == &APFloat::IEEEsingle()) OS << '<' << CSDN->getValueAPF().convertToFloat() << '>'; else if (&CSDN->getValueAPF().getSemantics() == &APFloat::IEEEdouble()) OS << '<' << CSDN->getValueAPF().convertToDouble() << '>'; else { OS << "getValueAPF().bitcastToAPInt().print(OS, false); OS << ")>"; } } else if (const GlobalAddressSDNode *GADN = dyn_cast(this)) { int64_t offset = GADN->getOffset(); OS << '<'; GADN->getGlobal()->printAsOperand(OS); OS << '>'; if (offset > 0) OS << " + " << offset; else OS << " " << offset; if (unsigned int TF = GADN->getTargetFlags()) OS << " [TF=" << TF << ']'; } else if (const FrameIndexSDNode *FIDN = dyn_cast(this)) { OS << "<" << FIDN->getIndex() << ">"; } else if (const JumpTableSDNode *JTDN = dyn_cast(this)) { OS << "<" << JTDN->getIndex() << ">"; if (unsigned int TF = JTDN->getTargetFlags()) OS << " [TF=" << TF << ']'; } else if (const ConstantPoolSDNode *CP = dyn_cast(this)){ int offset = CP->getOffset(); if (CP->isMachineConstantPoolEntry()) OS << "<" << *CP->getMachineCPVal() << ">"; else OS << "<" << *CP->getConstVal() << ">"; if (offset > 0) OS << " + " << offset; else OS << " " << offset; if (unsigned int TF = CP->getTargetFlags()) OS << " [TF=" << TF << ']'; } else if (const TargetIndexSDNode *TI = dyn_cast(this)) { OS << "<" << TI->getIndex() << '+' << TI->getOffset() << ">"; if (unsigned TF = TI->getTargetFlags()) OS << " [TF=" << TF << ']'; } else if (const BasicBlockSDNode *BBDN = dyn_cast(this)) { OS << "<"; const Value *LBB = (const Value*)BBDN->getBasicBlock()->getBasicBlock(); if (LBB) OS << LBB->getName() << " "; OS << (const void*)BBDN->getBasicBlock() << ">"; } else if (const RegisterSDNode *R = dyn_cast(this)) { OS << ' ' << printReg(R->getReg(), G ? G->getSubtarget().getRegisterInfo() : nullptr); } else if (const ExternalSymbolSDNode *ES = dyn_cast(this)) { OS << "'" << ES->getSymbol() << "'"; if (unsigned int TF = ES->getTargetFlags()) OS << " [TF=" << TF << ']'; } else if (const SrcValueSDNode *M = dyn_cast(this)) { if (M->getValue()) OS << "<" << M->getValue() << ">"; else OS << ""; } else if (const MDNodeSDNode *MD = dyn_cast(this)) { if (MD->getMD()) OS << "<" << MD->getMD() << ">"; else OS << ""; } else if (const VTSDNode *N = dyn_cast(this)) { OS << ":" << N->getVT().getEVTString(); } else if (const LoadSDNode *LD = dyn_cast(this)) { OS << "<"; printMemOperand(OS, *LD->getMemOperand(), G); bool doExt = true; switch (LD->getExtensionType()) { default: doExt = false; break; case ISD::EXTLOAD: OS << ", anyext"; break; case ISD::SEXTLOAD: OS << ", sext"; break; case ISD::ZEXTLOAD: OS << ", zext"; break; } if (doExt) OS << " from " << LD->getMemoryVT().getEVTString(); const char *AM = getIndexedModeName(LD->getAddressingMode()); if (*AM) OS << ", " << AM; OS << ">"; } else if (const StoreSDNode *ST = dyn_cast(this)) { OS << "<"; printMemOperand(OS, *ST->getMemOperand(), G); if (ST->isTruncatingStore()) OS << ", trunc to " << ST->getMemoryVT().getEVTString(); const char *AM = getIndexedModeName(ST->getAddressingMode()); if (*AM) OS << ", " << AM; OS << ">"; } else if (const MaskedLoadSDNode *MLd = dyn_cast(this)) { OS << "<"; printMemOperand(OS, *MLd->getMemOperand(), G); bool doExt = true; switch (MLd->getExtensionType()) { default: doExt = false; break; case ISD::EXTLOAD: OS << ", anyext"; break; case ISD::SEXTLOAD: OS << ", sext"; break; case ISD::ZEXTLOAD: OS << ", zext"; break; } if (doExt) OS << " from " << MLd->getMemoryVT().getEVTString(); const char *AM = getIndexedModeName(MLd->getAddressingMode()); if (*AM) OS << ", " << AM; if (MLd->isExpandingLoad()) OS << ", expanding"; OS << ">"; } else if (const MaskedStoreSDNode *MSt = dyn_cast(this)) { OS << "<"; printMemOperand(OS, *MSt->getMemOperand(), G); if (MSt->isTruncatingStore()) OS << ", trunc to " << MSt->getMemoryVT().getEVTString(); const char *AM = getIndexedModeName(MSt->getAddressingMode()); if (*AM) OS << ", " << AM; if (MSt->isCompressingStore()) OS << ", compressing"; OS << ">"; } else if (const auto *MGather = dyn_cast(this)) { OS << "<"; printMemOperand(OS, *MGather->getMemOperand(), G); bool doExt = true; switch (MGather->getExtensionType()) { default: doExt = false; break; case ISD::EXTLOAD: OS << ", anyext"; break; case ISD::SEXTLOAD: OS << ", sext"; break; case ISD::ZEXTLOAD: OS << ", zext"; break; } if (doExt) OS << " from " << MGather->getMemoryVT().getEVTString(); auto Signed = MGather->isIndexSigned() ? "signed" : "unsigned"; auto Scaled = MGather->isIndexScaled() ? "scaled" : "unscaled"; OS << ", " << Signed << " " << Scaled << " offset"; OS << ">"; } else if (const auto *MScatter = dyn_cast(this)) { OS << "<"; printMemOperand(OS, *MScatter->getMemOperand(), G); if (MScatter->isTruncatingStore()) OS << ", trunc to " << MScatter->getMemoryVT().getEVTString(); auto Signed = MScatter->isIndexSigned() ? "signed" : "unsigned"; auto Scaled = MScatter->isIndexScaled() ? "scaled" : "unscaled"; OS << ", " << Signed << " " << Scaled << " offset"; OS << ">"; } else if (const MemSDNode *M = dyn_cast(this)) { OS << "<"; printMemOperand(OS, *M->getMemOperand(), G); OS << ">"; } else if (const BlockAddressSDNode *BA = dyn_cast(this)) { int64_t offset = BA->getOffset(); OS << "<"; BA->getBlockAddress()->getFunction()->printAsOperand(OS, false); OS << ", "; BA->getBlockAddress()->getBasicBlock()->printAsOperand(OS, false); OS << ">"; if (offset > 0) OS << " + " << offset; else OS << " " << offset; if (unsigned int TF = BA->getTargetFlags()) OS << " [TF=" << TF << ']'; } else if (const AddrSpaceCastSDNode *ASC = dyn_cast(this)) { OS << '[' << ASC->getSrcAddressSpace() << " -> " << ASC->getDestAddressSpace() << ']'; } else if (const LifetimeSDNode *LN = dyn_cast(this)) { if (LN->hasOffset()) OS << "<" << LN->getOffset() << " to " << LN->getOffset() + LN->getSize() << ">"; } else if (const auto *AA = dyn_cast(this)) { OS << '<' << AA->getAlign().value() << '>'; } if (VerboseDAGDumping) { if (unsigned Order = getIROrder()) OS << " [ORD=" << Order << ']'; if (getNodeId() != -1) OS << " [ID=" << getNodeId() << ']'; if (!(isa(this) || (isa(this)))) OS << " # D:" << isDivergent(); if (G && !G->GetDbgValues(this).empty()) { OS << " [NoOfDbgValues=" << G->GetDbgValues(this).size() << ']'; for (SDDbgValue *Dbg : G->GetDbgValues(this)) if (!Dbg->isInvalidated()) Dbg->print(OS); } else if (getHasDebugValue()) OS << " [NoOfDbgValues>0]"; } } LLVM_DUMP_METHOD void SDDbgValue::print(raw_ostream &OS) const { OS << " DbgVal(Order=" << getOrder() << ')'; if (isInvalidated()) OS << "(Invalidated)"; if (isEmitted()) OS << "(Emitted)"; OS << "("; bool Comma = false; for (const SDDbgOperand &Op : getLocationOps()) { if (Comma) OS << ", "; switch (Op.getKind()) { case SDDbgOperand::SDNODE: if (Op.getSDNode()) OS << "SDNODE=" << PrintNodeId(*Op.getSDNode()) << ':' << Op.getResNo(); else OS << "SDNODE"; break; case SDDbgOperand::CONST: OS << "CONST"; break; case SDDbgOperand::FRAMEIX: OS << "FRAMEIX=" << Op.getFrameIx(); break; case SDDbgOperand::VREG: OS << "VREG=" << Op.getVReg(); break; } Comma = true; } OS << ")"; if (isIndirect()) OS << "(Indirect)"; if (isVariadic()) OS << "(Variadic)"; OS << ":\"" << Var->getName() << '"'; #ifndef NDEBUG if (Expr->getNumElements()) Expr->dump(); #endif } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void SDDbgValue::dump() const { if (isInvalidated()) return; print(dbgs()); dbgs() << "\n"; } #endif /// Return true if this node is so simple that we should just print it inline /// if it appears as an operand. static bool shouldPrintInline(const SDNode &Node, const SelectionDAG *G) { // Avoid lots of cluttering when inline printing nodes with associated // DbgValues in verbose mode. if (VerboseDAGDumping && G && !G->GetDbgValues(&Node).empty()) return false; if (Node.getOpcode() == ISD::EntryToken) return false; return Node.getNumOperands() == 0; } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) static void DumpNodes(const SDNode *N, unsigned indent, const SelectionDAG *G) { for (const SDValue &Op : N->op_values()) { if (shouldPrintInline(*Op.getNode(), G)) continue; if (Op.getNode()->hasOneUse()) DumpNodes(Op.getNode(), indent+2, G); } dbgs().indent(indent); N->dump(G); } LLVM_DUMP_METHOD void SelectionDAG::dump() const { dbgs() << "SelectionDAG has " << AllNodes.size() << " nodes:\n"; for (const SDNode &N : allnodes()) { if (!N.hasOneUse() && &N != getRoot().getNode() && (!shouldPrintInline(N, this) || N.use_empty())) DumpNodes(&N, 2, this); } if (getRoot().getNode()) DumpNodes(getRoot().getNode(), 2, this); dbgs() << "\n"; if (VerboseDAGDumping) { if (DbgBegin() != DbgEnd()) dbgs() << "SDDbgValues:\n"; for (auto *Dbg : make_range(DbgBegin(), DbgEnd())) Dbg->dump(); if (ByvalParmDbgBegin() != ByvalParmDbgEnd()) dbgs() << "Byval SDDbgValues:\n"; for (auto *Dbg : make_range(ByvalParmDbgBegin(), ByvalParmDbgEnd())) Dbg->dump(); } dbgs() << "\n"; } #endif void SDNode::printr(raw_ostream &OS, const SelectionDAG *G) const { OS << PrintNodeId(*this) << ": "; print_types(OS, G); OS << " = " << getOperationName(G); print_details(OS, G); } static bool printOperand(raw_ostream &OS, const SelectionDAG *G, const SDValue Value) { if (!Value.getNode()) { OS << ""; return false; } if (shouldPrintInline(*Value.getNode(), G)) { OS << Value->getOperationName(G) << ':'; Value->print_types(OS, G); Value->print_details(OS, G); return true; } OS << PrintNodeId(*Value.getNode()); if (unsigned RN = Value.getResNo()) OS << ':' << RN; return false; } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) using VisitedSDNodeSet = SmallPtrSet; static void DumpNodesr(raw_ostream &OS, const SDNode *N, unsigned indent, const SelectionDAG *G, VisitedSDNodeSet &once) { if (!once.insert(N).second) // If we've been here before, return now. return; // Dump the current SDNode, but don't end the line yet. OS.indent(indent); N->printr(OS, G); // Having printed this SDNode, walk the children: for (unsigned i = 0, e = N->getNumOperands(); i != e; ++i) { if (i) OS << ","; OS << " "; const SDValue Op = N->getOperand(i); bool printedInline = printOperand(OS, G, Op); if (printedInline) once.insert(Op.getNode()); } OS << "\n"; // Dump children that have grandchildren on their own line(s). for (const SDValue &Op : N->op_values()) DumpNodesr(OS, Op.getNode(), indent+2, G, once); } LLVM_DUMP_METHOD void SDNode::dumpr() const { VisitedSDNodeSet once; DumpNodesr(dbgs(), this, 0, nullptr, once); } LLVM_DUMP_METHOD void SDNode::dumpr(const SelectionDAG *G) const { VisitedSDNodeSet once; DumpNodesr(dbgs(), this, 0, G, once); } #endif static void printrWithDepthHelper(raw_ostream &OS, const SDNode *N, const SelectionDAG *G, unsigned depth, unsigned indent) { if (depth == 0) return; OS.indent(indent); N->print(OS, G); for (const SDValue &Op : N->op_values()) { // Don't follow chain operands. if (Op.getValueType() == MVT::Other) continue; OS << '\n'; printrWithDepthHelper(OS, Op.getNode(), G, depth - 1, indent + 2); } } void SDNode::printrWithDepth(raw_ostream &OS, const SelectionDAG *G, unsigned depth) const { printrWithDepthHelper(OS, this, G, depth, 0); } void SDNode::printrFull(raw_ostream &OS, const SelectionDAG *G) const { // Don't print impossibly deep things. printrWithDepth(OS, G, 10); } #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) LLVM_DUMP_METHOD void SDNode::dumprWithDepth(const SelectionDAG *G, unsigned depth) const { printrWithDepth(dbgs(), G, depth); } LLVM_DUMP_METHOD void SDNode::dumprFull(const SelectionDAG *G) const { // Don't print impossibly deep things. dumprWithDepth(G, 10); } #endif void SDNode::print(raw_ostream &OS, const SelectionDAG *G) const { printr(OS, G); // Under VerboseDAGDumping divergence will be printed always. if (isDivergent() && !VerboseDAGDumping) OS << " # D:1"; for (unsigned i = 0, e = getNumOperands(); i != e; ++i) { if (i) OS << ", "; else OS << " "; printOperand(OS, G, getOperand(i)); } if (DebugLoc DL = getDebugLoc()) { OS << ", "; DL.print(OS); } }