//===-- AMDGPUInstructions.td - Common instruction defs ---*- 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 contains instruction defs that are common to all hw codegen // targets. // //===----------------------------------------------------------------------===// class AddressSpacesImpl { int Flat = 0; int Global = 1; int Region = 2; int Local = 3; int Constant = 4; int Private = 5; int Constant32Bit = 6; } def AddrSpaces : AddressSpacesImpl; class AMDGPUInst pattern = []> : Instruction { field bit isRegisterLoad = 0; field bit isRegisterStore = 0; let Namespace = "AMDGPU"; let OutOperandList = outs; let InOperandList = ins; let AsmString = asm; let Pattern = pattern; let Itinerary = NullALU; // SoftFail is a field the disassembler can use to provide a way for // instructions to not match without killing the whole decode process. It is // mainly used for ARM, but Tablegen expects this field to exist or it fails // to build the decode table. field bits<96> SoftFail = 0; let DecoderNamespace = Namespace; let TSFlags{63} = isRegisterLoad; let TSFlags{62} = isRegisterStore; } class AMDGPUShaderInst pattern = []> : AMDGPUInst { field bits<32> Inst = 0xffffffff; } //===---------------------------------------------------------------------===// // Return instruction //===---------------------------------------------------------------------===// class ILFormat pattern> : Instruction { let Namespace = "AMDGPU"; dag OutOperandList = outs; dag InOperandList = ins; let Pattern = pattern; let AsmString = !strconcat(asmstr, "\n"); let isPseudo = 1; let Itinerary = NullALU; bit hasIEEEFlag = 0; bit hasZeroOpFlag = 0; let mayLoad = 0; let mayStore = 0; let hasSideEffects = 0; let isCodeGenOnly = 1; } def TruePredicate : Predicate<"">; // FIXME: Tablegen should specially supports this def FalsePredicate : Predicate<"false">; // Add a predicate to the list if does not already exist to deduplicate it. class PredConcat lst, Predicate pred> { list ret = !listconcat(lst, !listremove([pred], lst)); } // Get the union of two Register lists class RegListUnion lstA, list lstB> { list ret = !listconcat(lstA, !listremove(lstB, lstA)); } class PredicateControl { Predicate SubtargetPredicate = TruePredicate; Predicate AssemblerPredicate = TruePredicate; Predicate WaveSizePredicate = TruePredicate; list OtherPredicates = []; list Predicates = PredConcat< PredConcat.ret, AssemblerPredicate>.ret, WaveSizePredicate>.ret; } class AMDGPUPat : Pat, PredicateControl, GISelFlags; let GIIgnoreCopies = 1 in class AMDGPUPatIgnoreCopies : AMDGPUPat; let RecomputePerFunction = 1 in { def FP16Denormals : Predicate<"MF->getInfo()->getMode().FP64FP16Denormals != DenormalMode::getPreserveSign()">; def FP32Denormals : Predicate<"MF->getInfo()->getMode().FP32Denormals != DenormalMode::getPreserveSign()">; def FP64Denormals : Predicate<"MF->getInfo()->getMode().FP64FP16Denormals != DenormalMode::getPreserveSign()">; def NoFP16Denormals : Predicate<"MF->getInfo()->getMode().FP64FP16Denormals == DenormalMode::getPreserveSign()">; def NoFP32Denormals : Predicate<"MF->getInfo()->getMode().FP32Denormals == DenormalMode::getPreserveSign()">; def NoFP64Denormals : Predicate<"MF->getInfo()->getMode().FP64FP16Denormals == DenormalMode::getPreserveSign()">; def UnsafeFPMath : Predicate<"TM.Options.UnsafeFPMath">; } def FMA : Predicate<"Subtarget->hasFMA()">; def InstFlag : OperandWithDefaultOps ; def i1imm_0 : OperandWithDefaultOps; class CustomOperandClass : AsmOperandClass { let Name = name; let PredicateMethod = "is"#name; let ParserMethod = parserMethod; let RenderMethod = "addImmOperands"; let IsOptional = optional; let DefaultMethod = defaultMethod; } class CustomOperandProps { string ImmTy = "ImmTy"#name; string ParserMethod = "parse"#name; string DefaultValue = "0"; string DefaultMethod = "[this]() { return "# "AMDGPUOperand::CreateImm(this, "#DefaultValue#", SMLoc(), "# "AMDGPUOperand::"#ImmTy#"); }"; string PrintMethod = "print"#name; AsmOperandClass ParserMatchClass = CustomOperandClass; string OperandType = "OPERAND_IMMEDIATE"; } class CustomOperand : Operand, CustomOperandProps; class ImmOperand : CustomOperand { let ImmTy = "ImmTyNone"; let ParserMethod = ""; let PrintMethod = printer; } def s16imm : ImmOperand; def u16imm : ImmOperand; //===--------------------------------------------------------------------===// // Custom Operands //===--------------------------------------------------------------------===// def brtarget : Operand; //===----------------------------------------------------------------------===// // Misc. PatFrags //===----------------------------------------------------------------------===// class HasOneUseUnaryOp : PatFrag< (ops node:$src0), (op $src0), [{ return N->hasOneUse(); }]> { let GISelPredicateCode = [{ return MRI.hasOneNonDBGUse(MI.getOperand(0).getReg()); }]; } class HasOneUseBinOp : PatFrag< (ops node:$src0, node:$src1), (op $src0, $src1), [{ return N->hasOneUse(); }]> { let GISelPredicateCode = [{ return MRI.hasOneNonDBGUse(MI.getOperand(0).getReg()); }]; } class HasOneUseTernaryOp : PatFrag< (ops node:$src0, node:$src1, node:$src2), (op $src0, $src1, $src2), [{ return N->hasOneUse(); }]> { let GISelPredicateCode = [{ return MRI.hasOneNonDBGUse(MI.getOperand(0).getReg()); }]; } class is_canonicalized : PatFrag< (ops node:$src0, node:$src1), (op $src0, $src1), [{ const SITargetLowering &Lowering = *static_cast(getTargetLowering()); return Lowering.isCanonicalized(*CurDAG, N->getOperand(0)) && Lowering.isCanonicalized(*CurDAG, N->getOperand(1)); }]> { // TODO: Improve the Legalizer for g_build_vector in Global Isel to match this class let GISelPredicateCode = [{ const SITargetLowering *TLI = static_cast( MF.getSubtarget().getTargetLowering()); return TLI->isCanonicalized(MI.getOperand(1).getReg(), const_cast(MF)) && TLI->isCanonicalized(MI.getOperand(2).getReg(), const_cast(MF)); }]; } class FoldTernaryOpPat : PatFrag< (ops node:$src0, node:$src1, node:$src2), (op2 (op1 node:$src0, node:$src1), node:$src2) >; def imad : FoldTernaryOpPat; let Properties = [SDNPCommutative, SDNPAssociative] in { def smax_oneuse : HasOneUseBinOp; def smin_oneuse : HasOneUseBinOp; def umax_oneuse : HasOneUseBinOp; def umin_oneuse : HasOneUseBinOp; def fminnum_oneuse : HasOneUseBinOp; def fmaxnum_oneuse : HasOneUseBinOp; def fminnum_ieee_oneuse : HasOneUseBinOp; def fmaxnum_ieee_oneuse : HasOneUseBinOp; def and_oneuse : HasOneUseBinOp; def or_oneuse : HasOneUseBinOp; def xor_oneuse : HasOneUseBinOp; } // Properties = [SDNPCommutative, SDNPAssociative] def not_oneuse : HasOneUseUnaryOp; def add_oneuse : HasOneUseBinOp; def sub_oneuse : HasOneUseBinOp; def srl_oneuse : HasOneUseBinOp; def shl_oneuse : HasOneUseBinOp; def select_oneuse : HasOneUseTernaryOp