//===- TargetGlobalISel.td - Common code for GlobalISel ----*- tablegen -*-===// // // 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 file defines the target-independent interfaces used to support // SelectionDAG instruction selection patterns (specified in // TargetSelectionDAG.td) when generating GlobalISel instruction selectors. // // This is intended as a compatibility layer, to enable reuse of target // descriptions written for SelectionDAG without requiring explicit GlobalISel // support. It will eventually supersede SelectionDAG patterns. // //===----------------------------------------------------------------------===// // Declare that a generic Instruction is 'equivalent' to an SDNode, that is, // SelectionDAG patterns involving the SDNode can be transformed to match the // Instruction instead. class GINodeEquiv { Instruction I = i; SDNode Node = node; // SelectionDAG has separate nodes for atomic and non-atomic memory operations // (ISD::LOAD, ISD::ATOMIC_LOAD, ISD::STORE, ISD::ATOMIC_STORE) but GlobalISel // stores this information in the MachineMemoryOperand. bit CheckMMOIsNonAtomic = false; bit CheckMMOIsAtomic = false; // SelectionDAG has one node for all loads and uses predicates to // differentiate them. GlobalISel on the other hand uses separate opcodes. // When this is true, the resulting opcode is G_LOAD/G_SEXTLOAD/G_ZEXTLOAD // depending on the predicates on the node. Instruction IfSignExtend = ?; Instruction IfZeroExtend = ?; // SelectionDAG has one setcc for all compares. This differentiates // for G_ICMP and G_FCMP. Instruction IfFloatingPoint = ?; // SelectionDAG does not differentiate between convergent and non-convergent // intrinsics. This specifies an alternate opcode for a convergent intrinsic. Instruction IfConvergent = ?; } // These are defined in the same order as the G_* instructions. def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; // G_INTTOPTR - SelectionDAG has no equivalent. // G_PTRTOINT - SelectionDAG has no equivalent. def : GINodeEquiv; // timm must not be materialized and therefore has no GlobalISel equivalent def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv { let IfConvergent = G_INTRINSIC_CONVERGENT; } def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; // ISD::INTRINSIC_VOID can also be handled with G_INTRINSIC_W_SIDE_EFFECTS. let IfConvergent = G_INTRINSIC_CONVERGENT_W_SIDE_EFFECTS in { def : GINodeEquiv; def : GINodeEquiv; } def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; // Broadly speaking G_LOAD is equivalent to ISD::LOAD but there are some // complications that tablegen must take care of. For example, Predicates such // as isSignExtLoad require that this is not a perfect 1:1 mapping since a // sign-extending load is (G_SEXTLOAD x) in GlobalISel. Additionally, // G_LOAD handles both atomic and non-atomic loads where as SelectionDAG had // separate nodes for them. This GINodeEquiv maps the non-atomic loads to // G_LOAD with a non-atomic MachineMemOperand. def : GINodeEquiv { let CheckMMOIsNonAtomic = true; let IfSignExtend = G_SEXTLOAD; let IfZeroExtend = G_ZEXTLOAD; } def : GINodeEquiv { let IfFloatingPoint = G_FCMP; } // Broadly speaking G_STORE is equivalent to ISD::STORE but there are some // complications that tablegen must take care of. For example, predicates such // as isTruncStore require that this is not a perfect 1:1 mapping since a // truncating store is (G_STORE (G_TRUNCATE x)) in GlobalISel. Additionally, // G_STORE handles both atomic and non-atomic stores where as SelectionDAG had // separate nodes for them. This GINodeEquiv maps the non-atomic stores to // G_STORE with a non-atomic MachineMemOperand. def : GINodeEquiv { let CheckMMOIsNonAtomic = true; } def : GINodeEquiv { let CheckMMOIsNonAtomic = false; let CheckMMOIsAtomic = true; } def : GINodeEquiv { let CheckMMOIsNonAtomic = false; let CheckMMOIsAtomic = true; let IfSignExtend = G_SEXTLOAD; let IfZeroExtend = G_ZEXTLOAD; } def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; def : GINodeEquiv; // Specifies the GlobalISel equivalents for SelectionDAG's ComplexPattern. // Should be used on defs that subclass GIComplexOperandMatcher<>. class GIComplexPatternEquiv { ComplexPattern SelDAGEquivalent = seldag; } // Specifies the GlobalISel equivalents for SelectionDAG's SDNodeXForm. // Should be used on defs that subclass GICustomOperandRenderer<>. class GISDNodeXFormEquiv { SDNodeXForm SelDAGEquivalent = seldag; }