1//===-- VOPDInstructions.td - Vector Instruction Definitions --------------===// 2// 3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4// See https://llvm.org/LICENSE.txt for license information. 5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6// 7//===----------------------------------------------------------------------===// 8 9//===----------------------------------------------------------------------===// 10// Encodings 11//===----------------------------------------------------------------------===// 12 13class VOPDe<bits<4> opX, bits<5> opY> : Enc64 { 14 bits<9> src0X; 15 bits<8> vsrc1X; 16 bits<8> vdstX; 17 bits<9> src0Y; 18 bits<8> vsrc1Y; 19 bits<8> vdstY; 20 21 let Inst{8-0} = src0X; 22 let Inst{16-9} = vsrc1X; 23 let Inst{21-17} = opY; 24 let Inst{25-22} = opX; 25 let Inst{31-26} = 0x32; // encoding 26 let Inst{40-32} = src0Y; 27 let Inst{48-41} = vsrc1Y; 28 let Inst{55-49} = vdstY{7-1}; 29 let Inst{63-56} = vdstX; 30} 31 32class VOPD_MADKe<bits<4> opX, bits<5> opY> : Enc96 { 33 bits<9> src0X; 34 bits<8> vsrc1X; 35 bits<8> vdstX; 36 bits<9> src0Y; 37 bits<8> vsrc1Y; 38 bits<8> vdstY; 39 bits<32> imm; 40 41 let Inst{8-0} = src0X; 42 let Inst{16-9} = vsrc1X; 43 let Inst{21-17} = opY; 44 let Inst{25-22} = opX; 45 let Inst{31-26} = 0x32; // encoding 46 let Inst{40-32} = src0Y; 47 let Inst{48-41} = vsrc1Y; 48 let Inst{55-49} = vdstY{7-1}; 49 let Inst{63-56} = vdstX; 50 let Inst{95-64} = imm; 51} 52 53//===----------------------------------------------------------------------===// 54// VOPD classes 55//===----------------------------------------------------------------------===// 56 57 58class GFXGenD<GFXGen Gen, list<string> DXPseudos, list<string> DYPseudos, 59 Predicate subtargetPred = Gen.AssemblerPredicate> : 60 GFXGen<Gen.AssemblerPredicate, Gen.DecoderNamespace, Gen.Suffix, 61 Gen.Subtarget> { 62 list<string> VOPDXPseudos = DXPseudos; 63 list<string> VOPDYPseudos = DYPseudos; 64 Predicate SubtargetPredicate = subtargetPred; 65} 66 67class VOPD_Base<dag outs, dag ins, string asm, VOP_Pseudo VDX, VOP_Pseudo VDY, 68 VOPD_Component XasVC, VOPD_Component YasVC, GFXGenD Gen> 69 : VOPAnyCommon<outs, ins, asm, []>, 70 VOP<NAME>, 71 SIMCInstr<NAME, Gen.Subtarget> { 72 // Fields for table indexing 73 Instruction Opcode = !cast<Instruction>(NAME); 74 bits<5> OpX = XasVC.VOPDOp; 75 bits<5> OpY = YasVC.VOPDOp; 76 bits<4> SubTgt = Gen.Subtarget; 77 78 let VALU = 1; 79 80 let DecoderNamespace = Gen.DecoderNamespace; 81 let AssemblerPredicate = Gen.AssemblerPredicate; 82 let WaveSizePredicate = isWave32; 83 let isCodeGenOnly = 0; 84 let SubtargetPredicate = Gen.SubtargetPredicate; 85 let AsmMatchConverter = "cvtVOPD"; 86 let Size = 8; 87 let ReadsModeReg = !or(VDX.ReadsModeReg, VDY.ReadsModeReg); 88 let mayRaiseFPException = ReadsModeReg; 89 90 // V_DUAL_FMAC and V_DUAL_DOT2ACC_F32_F16 need a dummy src2 tied to dst for 91 // passes to track its uses. Its presence does not affect VOPD formation rules 92 // because the rules for src2 and dst are the same. src2X and src2Y should not 93 // be encoded. 94 bit hasSrc2AccX = !or(!eq(VDX.Mnemonic, "v_fmac_f32"), !eq(VDX.Mnemonic, "v_dot2c_f32_f16")); 95 bit hasSrc2AccY = !or(!eq(VDY.Mnemonic, "v_fmac_f32"), !eq(VDY.Mnemonic, "v_dot2c_f32_f16")); 96 string ConstraintsX = !if(hasSrc2AccX, "$src2X = $vdstX", ""); 97 string ConstraintsY = !if(hasSrc2AccY, "$src2Y = $vdstY", ""); 98 let Constraints = 99 ConstraintsX # !if(!and(hasSrc2AccX, hasSrc2AccY), ", ", "") # ConstraintsY; 100 string DisableEncodingX = !if(hasSrc2AccX, "$src2X", ""); 101 string DisableEncodingY = !if(hasSrc2AccY, "$src2Y", ""); 102 let DisableEncoding = 103 DisableEncodingX # !if(!and(hasSrc2AccX, hasSrc2AccY), ", ", "") # DisableEncodingY; 104 105 let Uses = RegListUnion<VDX.Uses, VDY.Uses>.ret; 106 let Defs = RegListUnion<VDX.Defs, VDY.Defs>.ret; 107 let SchedRW = !listconcat(VDX.SchedRW, VDY.SchedRW); 108} 109 110class VOPD<dag outs, dag ins, string asm, VOP_Pseudo VDX, VOP_Pseudo VDY, 111 VOPD_Component XasVC, VOPD_Component YasVC, GFXGenD Gen> 112 : VOPD_Base<outs, ins, asm, VDX, VDY, XasVC, YasVC, Gen>, 113 VOPDe<XasVC.VOPDOp{3-0}, YasVC.VOPDOp> { 114 let Inst{16-9} = !if (!eq(VDX.Mnemonic, "v_mov_b32"), 0x0, vsrc1X); 115 let Inst{48-41} = !if (!eq(VDY.Mnemonic, "v_mov_b32"), 0x0, vsrc1Y); 116} 117 118class VOPD_MADK<dag outs, dag ins, string asm, VOP_Pseudo VDX, VOP_Pseudo VDY, 119 VOPD_Component XasVC, VOPD_Component YasVC, GFXGenD Gen> 120 : VOPD_Base<outs, ins, asm, VDX, VDY, XasVC, YasVC, Gen>, 121 VOPD_MADKe<XasVC.VOPDOp{3-0}, YasVC.VOPDOp> { 122 let Inst{16-9} = !if (!eq(VDX.Mnemonic, "v_mov_b32"), 0x0, vsrc1X); 123 let Inst{48-41} = !if (!eq(VDY.Mnemonic, "v_mov_b32"), 0x0, vsrc1Y); 124 let Size = 12; 125 let FixedSize = 1; 126} 127 128// V_DUAL_DOT2ACC_F32_BF16 is a legal instruction, but V_DOT2ACC_F32_BF16 is 129// not. V_DUAL_DOT2C_F32_BF16 is a legal instruction on GFX12, but 130// V_DOT2C_F32_F16_e32 is not. Since we generate the DUAL form by converting 131// from the normal form we will never generate them. 132defvar VOPDPseudosCommon = [ 133 "V_FMAC_F32_e32", "V_FMAAK_F32", "V_FMAMK_F32", "V_MUL_F32_e32", 134 "V_ADD_F32_e32", "V_SUB_F32_e32", "V_SUBREV_F32_e32", "V_MUL_LEGACY_F32_e32", 135 "V_MOV_B32_e32", "V_CNDMASK_B32_e32", "V_MAX_F32_e32", "V_MIN_F32_e32" 136]; 137defvar VOPDPseudosGFX11 = ["V_DOT2C_F32_F16_e32"]; 138defvar VOPDYOnlyPseudosCommon = ["V_ADD_U32_e32", "V_LSHLREV_B32_e32", 139 "V_AND_B32_e32"]; 140 141defvar VOPDXPseudosGFX11 = !listconcat(VOPDPseudosCommon, VOPDPseudosGFX11); 142defvar VOPDXPseudosGFX12 = VOPDPseudosCommon; 143defvar VOPDYPseudosGFX11 = !listconcat(VOPDXPseudosGFX11, VOPDYOnlyPseudosCommon); 144defvar VOPDYPseudosGFX12 = !listconcat(VOPDXPseudosGFX12, VOPDYOnlyPseudosCommon); 145 146def GFX11GenD : GFXGenD<GFX11Gen, VOPDXPseudosGFX11, VOPDYPseudosGFX11>; 147def GFX12GenD : GFXGenD<GFX12Gen, VOPDXPseudosGFX12, VOPDYPseudosGFX12>; 148 149 150def VOPDDstYOperand : RegisterOperand<VGPR_32, "printRegularOperand"> { 151 let DecoderMethod = "decodeOperandVOPDDstY"; 152} 153 154class getRenamed<string VOPDName, GFXGen Gen> { 155 string ret = !if(!eq(Gen.Subtarget, GFX12Gen.Subtarget), 156 !if(!eq(VOPDName, "v_dual_max_f32"), 157 "v_dual_max_num_f32", 158 !if(!eq(VOPDName, "v_dual_min_f32"), 159 "v_dual_min_num_f32", 160 VOPDName)), 161 VOPDName); 162} 163 164foreach Gen = [GFX11GenD, GFX12GenD] in { 165 foreach x = Gen.VOPDXPseudos in { 166 foreach y = Gen.VOPDYPseudos in { 167 defvar xInst = !cast<VOP_Pseudo>(x); 168 defvar yInst = !cast<VOP_Pseudo>(y); 169 defvar XasVC = !cast<VOPD_Component>(x); 170 defvar YasVC = !cast<VOPD_Component>(y); 171 defvar xAsmName = getRenamed<XasVC.VOPDName, Gen>.ret; 172 defvar yAsmName = getRenamed<YasVC.VOPDName, Gen>.ret; 173 defvar isMADK = !or(!eq(x, "V_FMAAK_F32"), !eq(x, "V_FMAMK_F32"), 174 !eq(y, "V_FMAAK_F32"), !eq(y, "V_FMAMK_F32")); 175 // If X or Y is MADK (have a mandatory immediate), all src operands which 176 // may contain an optional literal must use the VSrc_*_Deferred operand 177 // type. Optional literal operands in MADK VOPD components always use this 178 // operand form. If Both X and Y are MADK, the mandatory literal of X 179 // additionally must use an alternate operand format which defers to the 180 // 'real' Y literal 181 defvar isOpXMADK = !or(!eq(x, "V_FMAAK_F32"), !eq(x, "V_FMAMK_F32")); 182 defvar isOpYMADK = !or(!eq(y, "V_FMAAK_F32"), !eq(y, "V_FMAMK_F32")); 183 defvar OpName = "V_DUAL_" # !substr(x,2) # "_X_" # !substr(y,2) # Gen.Suffix; 184 defvar outs = (outs VGPRSrc_32:$vdstX, VOPDDstYOperand:$vdstY); 185 if !or(isOpXMADK, isOpYMADK) then { 186 if !and(isOpXMADK, isOpYMADK) then { 187 defvar X_MADK_Pfl = !cast<VOP_MADK_Base>(xInst.Pfl); 188 defvar ins = !con(xInst.Pfl.InsVOPDXDeferred, yInst.Pfl.InsVOPDY); 189 defvar asm = xAsmName #" "# X_MADK_Pfl.AsmVOPDXDeferred #" :: "# yAsmName #" "# yInst.Pfl.AsmVOPDY; 190 def OpName : VOPD_MADK<outs, ins, asm, xInst, yInst, XasVC, YasVC, Gen>; 191 } else { 192 defvar asm = xAsmName #" "# xInst.Pfl.AsmVOPDX #" :: "# yAsmName #" "# yInst.Pfl.AsmVOPDY; 193 if isOpXMADK then { 194 assert !not(isOpYMADK), "Expected only OpX as MADK"; 195 defvar ins = !con(xInst.Pfl.InsVOPDX, yInst.Pfl.InsVOPDYDeferred); 196 def OpName : VOPD_MADK<outs, ins, asm, xInst, yInst, XasVC, YasVC, Gen>; 197 } else { 198 assert !not(isOpXMADK), "Expected only OpY as MADK"; 199 defvar ins = !con(xInst.Pfl.InsVOPDXDeferred, yInst.Pfl.InsVOPDY); 200 def OpName : VOPD_MADK<outs, ins, asm, xInst, yInst, XasVC, YasVC, Gen>; 201 } 202 } 203 } else { 204 defvar ins = !con(xInst.Pfl.InsVOPDX, yInst.Pfl.InsVOPDY); 205 defvar asm = xAsmName #" "# xInst.Pfl.AsmVOPDX #" :: "# yAsmName #" "# yInst.Pfl.AsmVOPDY; 206 def OpName : VOPD<outs, ins, asm, xInst, yInst, XasVC, YasVC, Gen>; 207 } 208 } 209 } 210} 211 212