181ad6265SDimitry Andric//===-- VOPDInstructions.td - Vector Instruction Definitions --------------===// 281ad6265SDimitry Andric// 381ad6265SDimitry Andric// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 481ad6265SDimitry Andric// See https://llvm.org/LICENSE.txt for license information. 581ad6265SDimitry Andric// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 681ad6265SDimitry Andric// 781ad6265SDimitry Andric//===----------------------------------------------------------------------===// 881ad6265SDimitry Andric 981ad6265SDimitry Andric//===----------------------------------------------------------------------===// 1081ad6265SDimitry Andric// Encodings 1181ad6265SDimitry Andric//===----------------------------------------------------------------------===// 1281ad6265SDimitry Andric 1381ad6265SDimitry Andricclass VOPDe<bits<4> opX, bits<5> opY> : Enc64 { 1481ad6265SDimitry Andric bits<9> src0X; 1581ad6265SDimitry Andric bits<8> vsrc1X; 1681ad6265SDimitry Andric bits<8> vdstX; 1781ad6265SDimitry Andric bits<9> src0Y; 1881ad6265SDimitry Andric bits<8> vsrc1Y; 1981ad6265SDimitry Andric bits<8> vdstY; 2081ad6265SDimitry Andric 2181ad6265SDimitry Andric let Inst{8-0} = src0X; 2281ad6265SDimitry Andric let Inst{16-9} = vsrc1X; 2381ad6265SDimitry Andric let Inst{21-17} = opY; 2481ad6265SDimitry Andric let Inst{25-22} = opX; 2581ad6265SDimitry Andric let Inst{31-26} = 0x32; // encoding 2681ad6265SDimitry Andric let Inst{40-32} = src0Y; 2781ad6265SDimitry Andric let Inst{48-41} = vsrc1Y; 2881ad6265SDimitry Andric let Inst{55-49} = vdstY{7-1}; 2981ad6265SDimitry Andric let Inst{63-56} = vdstX; 3081ad6265SDimitry Andric} 3181ad6265SDimitry Andric 3281ad6265SDimitry Andricclass VOPD_MADKe<bits<4> opX, bits<5> opY> : Enc96 { 3381ad6265SDimitry Andric bits<9> src0X; 3481ad6265SDimitry Andric bits<8> vsrc1X; 3581ad6265SDimitry Andric bits<8> vdstX; 3681ad6265SDimitry Andric bits<9> src0Y; 3781ad6265SDimitry Andric bits<8> vsrc1Y; 3881ad6265SDimitry Andric bits<8> vdstY; 3981ad6265SDimitry Andric bits<32> imm; 4081ad6265SDimitry Andric 4181ad6265SDimitry Andric let Inst{8-0} = src0X; 4281ad6265SDimitry Andric let Inst{16-9} = vsrc1X; 4381ad6265SDimitry Andric let Inst{21-17} = opY; 4481ad6265SDimitry Andric let Inst{25-22} = opX; 4581ad6265SDimitry Andric let Inst{31-26} = 0x32; // encoding 4681ad6265SDimitry Andric let Inst{40-32} = src0Y; 4781ad6265SDimitry Andric let Inst{48-41} = vsrc1Y; 4881ad6265SDimitry Andric let Inst{55-49} = vdstY{7-1}; 4981ad6265SDimitry Andric let Inst{63-56} = vdstX; 5081ad6265SDimitry Andric let Inst{95-64} = imm; 5181ad6265SDimitry Andric} 5281ad6265SDimitry Andric 5381ad6265SDimitry Andric//===----------------------------------------------------------------------===// 5481ad6265SDimitry Andric// VOPD classes 5581ad6265SDimitry Andric//===----------------------------------------------------------------------===// 5681ad6265SDimitry Andric 57*5f757f3fSDimitry Andric 58*5f757f3fSDimitry Andricclass GFXGenD<GFXGen Gen, list<string> DXPseudos, list<string> DYPseudos, 59*5f757f3fSDimitry Andric Predicate subtargetPred = Gen.AssemblerPredicate> : 60*5f757f3fSDimitry Andric GFXGen<Gen.AssemblerPredicate, Gen.DecoderNamespace, Gen.Suffix, 61*5f757f3fSDimitry Andric Gen.Subtarget> { 62*5f757f3fSDimitry Andric list<string> VOPDXPseudos = DXPseudos; 63*5f757f3fSDimitry Andric list<string> VOPDYPseudos = DYPseudos; 64*5f757f3fSDimitry Andric Predicate SubtargetPredicate = subtargetPred; 65*5f757f3fSDimitry Andric} 66*5f757f3fSDimitry Andric 6781ad6265SDimitry Andricclass VOPD_Base<dag outs, dag ins, string asm, VOP_Pseudo VDX, VOP_Pseudo VDY, 68*5f757f3fSDimitry Andric VOPD_Component XasVC, VOPD_Component YasVC, GFXGenD Gen> 6981ad6265SDimitry Andric : VOPAnyCommon<outs, ins, asm, []>, 7081ad6265SDimitry Andric VOP<NAME>, 71*5f757f3fSDimitry Andric SIMCInstr<NAME, Gen.Subtarget> { 7281ad6265SDimitry Andric // Fields for table indexing 7381ad6265SDimitry Andric Instruction Opcode = !cast<Instruction>(NAME); 7481ad6265SDimitry Andric bits<5> OpX = XasVC.VOPDOp; 7581ad6265SDimitry Andric bits<5> OpY = YasVC.VOPDOp; 76*5f757f3fSDimitry Andric bits<4> SubTgt = Gen.Subtarget; 7781ad6265SDimitry Andric 7881ad6265SDimitry Andric let VALU = 1; 7981ad6265SDimitry Andric 80*5f757f3fSDimitry Andric let DecoderNamespace = Gen.DecoderNamespace; 81*5f757f3fSDimitry Andric let AssemblerPredicate = Gen.AssemblerPredicate; 8281ad6265SDimitry Andric let WaveSizePredicate = isWave32; 8381ad6265SDimitry Andric let isCodeGenOnly = 0; 84*5f757f3fSDimitry Andric let SubtargetPredicate = Gen.SubtargetPredicate; 8581ad6265SDimitry Andric let AsmMatchConverter = "cvtVOPD"; 8681ad6265SDimitry Andric let Size = 8; 8781ad6265SDimitry Andric let ReadsModeReg = !or(VDX.ReadsModeReg, VDY.ReadsModeReg); 8881ad6265SDimitry Andric let mayRaiseFPException = ReadsModeReg; 8981ad6265SDimitry Andric 90bdd1243dSDimitry Andric // V_DUAL_FMAC and V_DUAL_DOT2ACC_F32_F16 need a dummy src2 tied to dst for 91bdd1243dSDimitry Andric // passes to track its uses. Its presence does not affect VOPD formation rules 92bdd1243dSDimitry Andric // because the rules for src2 and dst are the same. src2X and src2Y should not 93bdd1243dSDimitry Andric // be encoded. 94bdd1243dSDimitry Andric bit hasSrc2AccX = !or(!eq(VDX.Mnemonic, "v_fmac_f32"), !eq(VDX.Mnemonic, "v_dot2c_f32_f16")); 95bdd1243dSDimitry Andric bit hasSrc2AccY = !or(!eq(VDY.Mnemonic, "v_fmac_f32"), !eq(VDY.Mnemonic, "v_dot2c_f32_f16")); 96bdd1243dSDimitry Andric string ConstraintsX = !if(hasSrc2AccX, "$src2X = $vdstX", ""); 97bdd1243dSDimitry Andric string ConstraintsY = !if(hasSrc2AccY, "$src2Y = $vdstY", ""); 98bdd1243dSDimitry Andric let Constraints = 99bdd1243dSDimitry Andric ConstraintsX # !if(!and(hasSrc2AccX, hasSrc2AccY), ", ", "") # ConstraintsY; 100bdd1243dSDimitry Andric string DisableEncodingX = !if(hasSrc2AccX, "$src2X", ""); 101bdd1243dSDimitry Andric string DisableEncodingY = !if(hasSrc2AccY, "$src2Y", ""); 102bdd1243dSDimitry Andric let DisableEncoding = 103bdd1243dSDimitry Andric DisableEncodingX # !if(!and(hasSrc2AccX, hasSrc2AccY), ", ", "") # DisableEncodingY; 104bdd1243dSDimitry Andric 10581ad6265SDimitry Andric let Uses = RegListUnion<VDX.Uses, VDY.Uses>.ret; 10681ad6265SDimitry Andric let Defs = RegListUnion<VDX.Defs, VDY.Defs>.ret; 10781ad6265SDimitry Andric let SchedRW = !listconcat(VDX.SchedRW, VDY.SchedRW); 10881ad6265SDimitry Andric} 10981ad6265SDimitry Andric 11081ad6265SDimitry Andricclass VOPD<dag outs, dag ins, string asm, VOP_Pseudo VDX, VOP_Pseudo VDY, 111*5f757f3fSDimitry Andric VOPD_Component XasVC, VOPD_Component YasVC, GFXGenD Gen> 112*5f757f3fSDimitry Andric : VOPD_Base<outs, ins, asm, VDX, VDY, XasVC, YasVC, Gen>, 11381ad6265SDimitry Andric VOPDe<XasVC.VOPDOp{3-0}, YasVC.VOPDOp> { 11481ad6265SDimitry Andric let Inst{16-9} = !if (!eq(VDX.Mnemonic, "v_mov_b32"), 0x0, vsrc1X); 11581ad6265SDimitry Andric let Inst{48-41} = !if (!eq(VDY.Mnemonic, "v_mov_b32"), 0x0, vsrc1Y); 11681ad6265SDimitry Andric} 11781ad6265SDimitry Andric 11881ad6265SDimitry Andricclass VOPD_MADK<dag outs, dag ins, string asm, VOP_Pseudo VDX, VOP_Pseudo VDY, 119*5f757f3fSDimitry Andric VOPD_Component XasVC, VOPD_Component YasVC, GFXGenD Gen> 120*5f757f3fSDimitry Andric : VOPD_Base<outs, ins, asm, VDX, VDY, XasVC, YasVC, Gen>, 12181ad6265SDimitry Andric VOPD_MADKe<XasVC.VOPDOp{3-0}, YasVC.VOPDOp> { 12281ad6265SDimitry Andric let Inst{16-9} = !if (!eq(VDX.Mnemonic, "v_mov_b32"), 0x0, vsrc1X); 12381ad6265SDimitry Andric let Inst{48-41} = !if (!eq(VDY.Mnemonic, "v_mov_b32"), 0x0, vsrc1Y); 12481ad6265SDimitry Andric let Size = 12; 125*5f757f3fSDimitry Andric let FixedSize = 1; 12681ad6265SDimitry Andric} 12781ad6265SDimitry Andric 12881ad6265SDimitry Andric// V_DUAL_DOT2ACC_F32_BF16 is a legal instruction, but V_DOT2ACC_F32_BF16 is 129*5f757f3fSDimitry Andric// not. V_DUAL_DOT2C_F32_BF16 is a legal instruction on GFX12, but 130*5f757f3fSDimitry Andric// V_DOT2C_F32_F16_e32 is not. Since we generate the DUAL form by converting 131*5f757f3fSDimitry Andric// from the normal form we will never generate them. 132*5f757f3fSDimitry Andricdefvar VOPDPseudosCommon = [ 13381ad6265SDimitry Andric "V_FMAC_F32_e32", "V_FMAAK_F32", "V_FMAMK_F32", "V_MUL_F32_e32", 13481ad6265SDimitry Andric "V_ADD_F32_e32", "V_SUB_F32_e32", "V_SUBREV_F32_e32", "V_MUL_LEGACY_F32_e32", 135*5f757f3fSDimitry Andric "V_MOV_B32_e32", "V_CNDMASK_B32_e32", "V_MAX_F32_e32", "V_MIN_F32_e32" 13681ad6265SDimitry Andric]; 137*5f757f3fSDimitry Andricdefvar VOPDPseudosGFX11 = ["V_DOT2C_F32_F16_e32"]; 138*5f757f3fSDimitry Andricdefvar VOPDYOnlyPseudosCommon = ["V_ADD_U32_e32", "V_LSHLREV_B32_e32", 139*5f757f3fSDimitry Andric "V_AND_B32_e32"]; 140*5f757f3fSDimitry Andric 141*5f757f3fSDimitry Andricdefvar VOPDXPseudosGFX11 = !listconcat(VOPDPseudosCommon, VOPDPseudosGFX11); 142*5f757f3fSDimitry Andricdefvar VOPDXPseudosGFX12 = VOPDPseudosCommon; 143*5f757f3fSDimitry Andricdefvar VOPDYPseudosGFX11 = !listconcat(VOPDXPseudosGFX11, VOPDYOnlyPseudosCommon); 144*5f757f3fSDimitry Andricdefvar VOPDYPseudosGFX12 = !listconcat(VOPDXPseudosGFX12, VOPDYOnlyPseudosCommon); 145*5f757f3fSDimitry Andric 146*5f757f3fSDimitry Andricdef GFX11GenD : GFXGenD<GFX11Gen, VOPDXPseudosGFX11, VOPDYPseudosGFX11>; 147*5f757f3fSDimitry Andricdef GFX12GenD : GFXGenD<GFX12Gen, VOPDXPseudosGFX12, VOPDYPseudosGFX12>; 148*5f757f3fSDimitry Andric 14981ad6265SDimitry Andric 15081ad6265SDimitry Andricdef VOPDDstYOperand : RegisterOperand<VGPR_32, "printRegularOperand"> { 15181ad6265SDimitry Andric let DecoderMethod = "decodeOperandVOPDDstY"; 15281ad6265SDimitry Andric} 15381ad6265SDimitry Andric 154*5f757f3fSDimitry Andricclass getRenamed<string VOPDName, GFXGen Gen> { 155*5f757f3fSDimitry Andric string ret = !if(!eq(Gen.Subtarget, GFX12Gen.Subtarget), 156*5f757f3fSDimitry Andric !if(!eq(VOPDName, "v_dual_max_f32"), 157*5f757f3fSDimitry Andric "v_dual_max_num_f32", 158*5f757f3fSDimitry Andric !if(!eq(VOPDName, "v_dual_min_f32"), 159*5f757f3fSDimitry Andric "v_dual_min_num_f32", 160*5f757f3fSDimitry Andric VOPDName)), 161*5f757f3fSDimitry Andric VOPDName); 162*5f757f3fSDimitry Andric} 163*5f757f3fSDimitry Andric 164*5f757f3fSDimitry Andricforeach Gen = [GFX11GenD, GFX12GenD] in { 165*5f757f3fSDimitry Andric foreach x = Gen.VOPDXPseudos in { 166*5f757f3fSDimitry Andric foreach y = Gen.VOPDYPseudos in { 16781ad6265SDimitry Andric defvar xInst = !cast<VOP_Pseudo>(x); 16881ad6265SDimitry Andric defvar yInst = !cast<VOP_Pseudo>(y); 16981ad6265SDimitry Andric defvar XasVC = !cast<VOPD_Component>(x); 17081ad6265SDimitry Andric defvar YasVC = !cast<VOPD_Component>(y); 171*5f757f3fSDimitry Andric defvar xAsmName = getRenamed<XasVC.VOPDName, Gen>.ret; 172*5f757f3fSDimitry Andric defvar yAsmName = getRenamed<YasVC.VOPDName, Gen>.ret; 17381ad6265SDimitry Andric defvar isMADK = !or(!eq(x, "V_FMAAK_F32"), !eq(x, "V_FMAMK_F32"), 17481ad6265SDimitry Andric !eq(y, "V_FMAAK_F32"), !eq(y, "V_FMAMK_F32")); 17581ad6265SDimitry Andric // If X or Y is MADK (have a mandatory immediate), all src operands which 17681ad6265SDimitry Andric // may contain an optional literal must use the VSrc_*_Deferred operand 17781ad6265SDimitry Andric // type. Optional literal operands in MADK VOPD components always use this 17881ad6265SDimitry Andric // operand form. If Both X and Y are MADK, the mandatory literal of X 17981ad6265SDimitry Andric // additionally must use an alternate operand format which defers to the 18081ad6265SDimitry Andric // 'real' Y literal 18181ad6265SDimitry Andric defvar isOpXMADK = !or(!eq(x, "V_FMAAK_F32"), !eq(x, "V_FMAMK_F32")); 18281ad6265SDimitry Andric defvar isOpYMADK = !or(!eq(y, "V_FMAAK_F32"), !eq(y, "V_FMAMK_F32")); 183*5f757f3fSDimitry Andric defvar OpName = "V_DUAL_" # !substr(x,2) # "_X_" # !substr(y,2) # Gen.Suffix; 18481ad6265SDimitry Andric defvar outs = (outs VGPRSrc_32:$vdstX, VOPDDstYOperand:$vdstY); 18581ad6265SDimitry Andric if !or(isOpXMADK, isOpYMADK) then { 18681ad6265SDimitry Andric if !and(isOpXMADK, isOpYMADK) then { 18781ad6265SDimitry Andric defvar X_MADK_Pfl = !cast<VOP_MADK_Base>(xInst.Pfl); 18881ad6265SDimitry Andric defvar ins = !con(xInst.Pfl.InsVOPDXDeferred, yInst.Pfl.InsVOPDY); 189*5f757f3fSDimitry Andric defvar asm = xAsmName #" "# X_MADK_Pfl.AsmVOPDXDeferred #" :: "# yAsmName #" "# yInst.Pfl.AsmVOPDY; 190*5f757f3fSDimitry Andric def OpName : VOPD_MADK<outs, ins, asm, xInst, yInst, XasVC, YasVC, Gen>; 19181ad6265SDimitry Andric } else { 192*5f757f3fSDimitry Andric defvar asm = xAsmName #" "# xInst.Pfl.AsmVOPDX #" :: "# yAsmName #" "# yInst.Pfl.AsmVOPDY; 19381ad6265SDimitry Andric if isOpXMADK then { 19481ad6265SDimitry Andric assert !not(isOpYMADK), "Expected only OpX as MADK"; 19581ad6265SDimitry Andric defvar ins = !con(xInst.Pfl.InsVOPDX, yInst.Pfl.InsVOPDYDeferred); 196*5f757f3fSDimitry Andric def OpName : VOPD_MADK<outs, ins, asm, xInst, yInst, XasVC, YasVC, Gen>; 19781ad6265SDimitry Andric } else { 19881ad6265SDimitry Andric assert !not(isOpXMADK), "Expected only OpY as MADK"; 19981ad6265SDimitry Andric defvar ins = !con(xInst.Pfl.InsVOPDXDeferred, yInst.Pfl.InsVOPDY); 200*5f757f3fSDimitry Andric def OpName : VOPD_MADK<outs, ins, asm, xInst, yInst, XasVC, YasVC, Gen>; 20181ad6265SDimitry Andric } 20281ad6265SDimitry Andric } 20381ad6265SDimitry Andric } else { 20481ad6265SDimitry Andric defvar ins = !con(xInst.Pfl.InsVOPDX, yInst.Pfl.InsVOPDY); 205*5f757f3fSDimitry Andric defvar asm = xAsmName #" "# xInst.Pfl.AsmVOPDX #" :: "# yAsmName #" "# yInst.Pfl.AsmVOPDY; 206*5f757f3fSDimitry Andric def OpName : VOPD<outs, ins, asm, xInst, yInst, XasVC, YasVC, Gen>; 207*5f757f3fSDimitry Andric } 20881ad6265SDimitry Andric } 20981ad6265SDimitry Andric } 21081ad6265SDimitry Andric} 21181ad6265SDimitry Andric 212