//===-- VOPDInstructions.td - Vector Instruction Definitions --------------===// // // 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 // //===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===// // Encodings //===----------------------------------------------------------------------===// class VOPDe opX, bits<5> opY> : Enc64 { bits<9> src0X; bits<8> vsrc1X; bits<8> vdstX; bits<9> src0Y; bits<8> vsrc1Y; bits<8> vdstY; let Inst{8-0} = src0X; let Inst{16-9} = vsrc1X; let Inst{21-17} = opY; let Inst{25-22} = opX; let Inst{31-26} = 0x32; // encoding let Inst{40-32} = src0Y; let Inst{48-41} = vsrc1Y; let Inst{55-49} = vdstY{7-1}; let Inst{63-56} = vdstX; } class VOPD_MADKe opX, bits<5> opY> : Enc96 { bits<9> src0X; bits<8> vsrc1X; bits<8> vdstX; bits<9> src0Y; bits<8> vsrc1Y; bits<8> vdstY; bits<32> imm; let Inst{8-0} = src0X; let Inst{16-9} = vsrc1X; let Inst{21-17} = opY; let Inst{25-22} = opX; let Inst{31-26} = 0x32; // encoding let Inst{40-32} = src0Y; let Inst{48-41} = vsrc1Y; let Inst{55-49} = vdstY{7-1}; let Inst{63-56} = vdstX; let Inst{95-64} = imm; } //===----------------------------------------------------------------------===// // VOPD classes //===----------------------------------------------------------------------===// class VOPD_Base : VOPAnyCommon, VOP, SIMCInstr { // Fields for table indexing Instruction Opcode = !cast(NAME); bits<5> OpX = XasVC.VOPDOp; bits<5> OpY = YasVC.VOPDOp; let VALU = 1; let DecoderNamespace = "GFX11"; let AssemblerPredicate = isGFX11Plus; let WaveSizePredicate = isWave32; let isCodeGenOnly = 0; let SubtargetPredicate = isGFX11Plus; let AsmMatchConverter = "cvtVOPD"; let Size = 8; let ReadsModeReg = !or(VDX.ReadsModeReg, VDY.ReadsModeReg); let mayRaiseFPException = ReadsModeReg; // V_DUAL_FMAC and V_DUAL_DOT2ACC_F32_F16 need a dummy src2 tied to dst for // passes to track its uses. Its presence does not affect VOPD formation rules // because the rules for src2 and dst are the same. src2X and src2Y should not // be encoded. bit hasSrc2AccX = !or(!eq(VDX.Mnemonic, "v_fmac_f32"), !eq(VDX.Mnemonic, "v_dot2c_f32_f16")); bit hasSrc2AccY = !or(!eq(VDY.Mnemonic, "v_fmac_f32"), !eq(VDY.Mnemonic, "v_dot2c_f32_f16")); string ConstraintsX = !if(hasSrc2AccX, "$src2X = $vdstX", ""); string ConstraintsY = !if(hasSrc2AccY, "$src2Y = $vdstY", ""); let Constraints = ConstraintsX # !if(!and(hasSrc2AccX, hasSrc2AccY), ", ", "") # ConstraintsY; string DisableEncodingX = !if(hasSrc2AccX, "$src2X", ""); string DisableEncodingY = !if(hasSrc2AccY, "$src2Y", ""); let DisableEncoding = DisableEncodingX # !if(!and(hasSrc2AccX, hasSrc2AccY), ", ", "") # DisableEncodingY; let Uses = RegListUnion.ret; let Defs = RegListUnion.ret; let SchedRW = !listconcat(VDX.SchedRW, VDY.SchedRW); } class VOPD : VOPD_Base, VOPDe { let Inst{16-9} = !if (!eq(VDX.Mnemonic, "v_mov_b32"), 0x0, vsrc1X); let Inst{48-41} = !if (!eq(VDY.Mnemonic, "v_mov_b32"), 0x0, vsrc1Y); } class VOPD_MADK : VOPD_Base, VOPD_MADKe { let Inst{16-9} = !if (!eq(VDX.Mnemonic, "v_mov_b32"), 0x0, vsrc1X); let Inst{48-41} = !if (!eq(VDY.Mnemonic, "v_mov_b32"), 0x0, vsrc1Y); let Size = 12; } // V_DUAL_DOT2ACC_F32_BF16 is a legal instruction, but V_DOT2ACC_F32_BF16 is // not. Since we generate the DUAL form by converting from the normal form we // will never generate it. defvar VOPDYPseudos = [ "V_FMAC_F32_e32", "V_FMAAK_F32", "V_FMAMK_F32", "V_MUL_F32_e32", "V_ADD_F32_e32", "V_SUB_F32_e32", "V_SUBREV_F32_e32", "V_MUL_LEGACY_F32_e32", "V_MOV_B32_e32", "V_CNDMASK_B32_e32", "V_MAX_F32_e32", "V_MIN_F32_e32", "V_DOT2C_F32_F16_e32", "V_ADD_U32_e32", "V_LSHLREV_B32_e32", "V_AND_B32_e32" ]; defvar VOPDXPseudos = VOPDYPseudos[0...VOPDX_Max_Index]; def VOPDDstYOperand : RegisterOperand { let DecoderMethod = "decodeOperandVOPDDstY"; } foreach x = VOPDXPseudos in { foreach y = VOPDYPseudos in { defvar xInst = !cast(x); defvar yInst = !cast(y); defvar XasVC = !cast(x); defvar YasVC = !cast(y); defvar isMADK = !or(!eq(x, "V_FMAAK_F32"), !eq(x, "V_FMAMK_F32"), !eq(y, "V_FMAAK_F32"), !eq(y, "V_FMAMK_F32")); // If X or Y is MADK (have a mandatory immediate), all src operands which // may contain an optional literal must use the VSrc_*_Deferred operand // type. Optional literal operands in MADK VOPD components always use this // operand form. If Both X and Y are MADK, the mandatory literal of X // additionally must use an alternate operand format which defers to the // 'real' Y literal defvar isOpXMADK = !or(!eq(x, "V_FMAAK_F32"), !eq(x, "V_FMAMK_F32")); defvar isOpYMADK = !or(!eq(y, "V_FMAAK_F32"), !eq(y, "V_FMAMK_F32")); defvar OpName = "V_DUAL_" # !substr(x,2) # "_X_" # !substr(y,2); defvar outs = (outs VGPRSrc_32:$vdstX, VOPDDstYOperand:$vdstY); if !or(isOpXMADK, isOpYMADK) then { if !and(isOpXMADK, isOpYMADK) then { defvar X_MADK_Pfl = !cast(xInst.Pfl); defvar ins = !con(xInst.Pfl.InsVOPDXDeferred, yInst.Pfl.InsVOPDY); defvar asm = XasVC.VOPDName #" "# X_MADK_Pfl.AsmVOPDXDeferred #" :: "# YasVC.VOPDName #" "# yInst.Pfl.AsmVOPDY; def OpName : VOPD_MADK; } else { defvar asm = XasVC.VOPDName #" "# xInst.Pfl.AsmVOPDX #" :: "# YasVC.VOPDName #" "# yInst.Pfl.AsmVOPDY; if isOpXMADK then { assert !not(isOpYMADK), "Expected only OpX as MADK"; defvar ins = !con(xInst.Pfl.InsVOPDX, yInst.Pfl.InsVOPDYDeferred); def OpName : VOPD_MADK; } else { assert !not(isOpXMADK), "Expected only OpY as MADK"; defvar ins = !con(xInst.Pfl.InsVOPDXDeferred, yInst.Pfl.InsVOPDY); def OpName : VOPD_MADK; } } } else { defvar ins = !con(xInst.Pfl.InsVOPDX, yInst.Pfl.InsVOPDY); defvar asm = XasVC.VOPDName #" "# xInst.Pfl.AsmVOPDX #" :: "# YasVC.VOPDName #" "# yInst.Pfl.AsmVOPDY; def OpName : VOPD; } } }