Index: llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp =================================================================== --- llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp +++ llvm/lib/Target/AMDGPU/AsmParser/AMDGPUAsmParser.cpp @@ -3590,7 +3590,7 @@ : MCRegister::NoRegister; }; - auto InstInfo = getVOPDInstInfo(Opcode, &MII); + const auto &InstInfo = getVOPDInstInfo(Opcode, &MII); auto InvalidOperandInfo = InstInfo.getInvalidOperandIndex(getVRegIdx); if (!InvalidOperandInfo) return true; @@ -8524,11 +8524,11 @@ for (auto CompIdx : VOPD::COMPONENTS) { const auto &CInfo = InstInfo[CompIdx]; - bool CompHasSrc2Acc = CInfo.hasSrc2Acc(); - auto SrcOperandsNum = InstInfo[CompIdx].getSrcOperandsNum(); - for (unsigned SrcIdx = 0; SrcIdx < SrcOperandsNum; ++SrcIdx) { - addOp(CInfo.getParsedSrcIndex(SrcIdx, CompHasSrc2Acc)); - } + auto ParsedSrcOperandsNum = InstInfo[CompIdx].getParsedSrcOperandsNum(); + for (unsigned SrcIdx = 0; SrcIdx < ParsedSrcOperandsNum; ++SrcIdx) + addOp(CInfo.getParsedSrcIndex(SrcIdx)); + if (CInfo.hasSrc2Acc()) + addOp(CInfo.getParsedDstIndex()); } } Index: llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h =================================================================== --- llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h +++ llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.h @@ -529,6 +529,40 @@ constexpr unsigned COMPONENTS[] = {ComponentIndex::X, ComponentIndex::Y}; constexpr unsigned COMPONENTS_NUM = 2; +// Properties of VOPD components. +class ComponentProps { +private: + unsigned SrcOperandsNum = 0; + Optional MandatoryLiteralIdx; + bool HasSrc2Acc = false; + +public: + ComponentProps() = default; + ComponentProps(const MCInstrDesc &OpDesc); + + unsigned getSrcOperandsNum() const { return SrcOperandsNum; } + unsigned getParsedSrcOperandsNum() const { + return SrcOperandsNum - HasSrc2Acc; + } + bool hasMandatoryLiteral() const { return MandatoryLiteralIdx.has_value(); } + unsigned getMandatoryLiteralIndex() const { + assert(hasMandatoryLiteral()); + return *MandatoryLiteralIdx; + } + bool hasRegSrcOperand(unsigned SrcIdx) const { + assert(SrcIdx < Component::MAX_SRC_NUM); + return SrcOperandsNum > SrcIdx && !hasMandatoryLiteralAt(SrcIdx); + } + bool hasSrc2Acc() const { return HasSrc2Acc; } + +private: + bool hasMandatoryLiteralAt(unsigned SrcIdx) const { + assert(SrcIdx < Component::MAX_SRC_NUM); + return hasMandatoryLiteral() && + *MandatoryLiteralIdx == Component::DST_NUM + SrcIdx; + } +}; + enum ComponentKind : unsigned { SINGLE = 0, // A single VOP1 or VOP2 instruction which may be used in VOPD. COMPONENT_X, // A VOPD instruction, X component. @@ -546,7 +580,7 @@ // dstX, dstY, src0X [, other OpX operands], src0Y [, other OpY operands] // Each ComponentKind has operand indices defined below. static constexpr unsigned MC_DST_IDX[] = {0, 0, 1}; - static constexpr unsigned FIRST_MC_SRC_IDX[] = {1, 2, 2 /* + OpXSrcNum */}; + static constexpr unsigned FIRST_MC_SRC_IDX[] = {1, 2, 2 /* + OpX.SrcNum */}; // Parsed operands of regular instructions are ordered as follows: // Mnemo dst src0 [vsrc1 ...] @@ -555,81 +589,58 @@ // OpYMnemo dstY src0Y [vsrc1Y|imm vsrc1Y|vsrc1Y imm] // Each ComponentKind has operand indices defined below. static constexpr unsigned PARSED_DST_IDX[] = {1, 1, - 4 /* + ParsedOpXSrcNum */}; + 4 /* + OpX.ParsedSrcNum */}; static constexpr unsigned FIRST_PARSED_SRC_IDX[] = { - 2, 2, 5 /* + ParsedOpXSrcNum */}; + 2, 2, 5 /* + OpX.ParsedSrcNum */}; private: - ComponentKind Kind; - unsigned OpXSrcNum; - unsigned ParsedOpXSrcNum; + const ComponentKind Kind; + const ComponentProps PrevOp; public: - ComponentLayout(ComponentKind Kind = ComponentKind::SINGLE, - unsigned OpXSrcNum = 0, unsigned ParsedOpXSrcNum = 0) - : Kind(Kind), OpXSrcNum(OpXSrcNum), ParsedOpXSrcNum(ParsedOpXSrcNum) { - assert(Kind <= ComponentKind::MAX); - assert((Kind == ComponentKind::COMPONENT_Y) == (OpXSrcNum > 0)); + // Create layout for COMPONENT_X or SINGLE component + ComponentLayout(ComponentKind Kind) : Kind(Kind) { + assert(Kind == ComponentKind::SINGLE || Kind == ComponentKind::COMPONENT_X); } + // Create layout for COMPONENT_Y which depends on COMPONENT_X layout + ComponentLayout(const ComponentProps &OpXProps) + : Kind(ComponentKind::COMPONENT_Y), PrevOp(OpXProps) {} + public: unsigned getDstIndex() const { return MC_DST_IDX[Kind]; } unsigned getSrcIndex(unsigned SrcIdx) const { assert(SrcIdx < Component::MAX_SRC_NUM); - return FIRST_MC_SRC_IDX[Kind] + OpXSrcNum + SrcIdx; + return FIRST_MC_SRC_IDX[Kind] + getPrevOpSrcNum() + SrcIdx; } unsigned getParsedDstIndex() const { - return PARSED_DST_IDX[Kind] + ParsedOpXSrcNum; + return PARSED_DST_IDX[Kind] + getPrevOpParsedSrcNum(); } - unsigned getParsedSrcIndex(unsigned SrcIdx, bool ComponentHasSrc2Acc) const { + unsigned getParsedSrcIndex(unsigned SrcIdx) const { assert(SrcIdx < Component::MAX_SRC_NUM); - // FMAC and DOT2C have a src2 operand on the MCInst but - // not on the asm representation. src2 is tied to dst. - if (ComponentHasSrc2Acc && SrcIdx == (MAX_SRC_NUM - 1)) - return getParsedDstIndex(); - return FIRST_PARSED_SRC_IDX[Kind] + ParsedOpXSrcNum + SrcIdx; + return FIRST_PARSED_SRC_IDX[Kind] + getPrevOpParsedSrcNum() + SrcIdx; } -}; -// Properties of VOPD components. -class ComponentProps { private: - unsigned SrcOperandsNum; - Optional MandatoryLiteralIdx; - bool HasSrc2Acc; - -public: - ComponentProps(const MCInstrDesc &OpDesc); - - unsigned getSrcOperandsNum() const { return SrcOperandsNum; } - bool hasMandatoryLiteral() const { return MandatoryLiteralIdx.has_value(); } - unsigned getMandatoryLiteralIndex() const { - assert(hasMandatoryLiteral()); - return *MandatoryLiteralIdx; - } - bool hasRegularSrcOperand(unsigned SrcIdx) const { - assert(SrcIdx < Component::MAX_SRC_NUM); - return SrcOperandsNum > SrcIdx && !hasMandatoryLiteralAt(SrcIdx); - } - bool hasSrc2Acc() const { return HasSrc2Acc; } - -private: - bool hasMandatoryLiteralAt(unsigned SrcIdx) const { - assert(SrcIdx < Component::MAX_SRC_NUM); - return hasMandatoryLiteral() && - *MandatoryLiteralIdx == Component::DST_NUM + SrcIdx; + unsigned getPrevOpSrcNum() const { return PrevOp.getSrcOperandsNum(); } + unsigned getPrevOpParsedSrcNum() const { + return PrevOp.getParsedSrcOperandsNum(); } }; // Layout and properties of VOPD components. class ComponentInfo : public ComponentLayout, public ComponentProps { public: + // Create ComponentInfo for COMPONENT_X or SINGLE component + ComponentInfo(const MCInstrDesc &OpDesc, + ComponentKind Kind = ComponentKind::SINGLE) + : ComponentLayout(Kind), ComponentProps(OpDesc) {} + + // Create ComponentInfo for COMPONENT_Y which depends on COMPONENT_X layout ComponentInfo(const MCInstrDesc &OpDesc, - ComponentKind Kind = ComponentKind::SINGLE, - unsigned OpXSrcNum = 0, unsigned ParsedOpXSrcNum = 0) - : ComponentLayout(Kind, OpXSrcNum, ParsedOpXSrcNum), - ComponentProps(OpDesc) {} + const ComponentProps &OpXProps) + : ComponentLayout(OpXProps), ComponentProps(OpDesc) {} // Map MC operand index to parsed operand index. // Return 0 if the specified operand does not exist. Index: llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp =================================================================== --- llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp +++ llvm/lib/Target/AMDGPU/Utils/AMDGPUBaseInfo.cpp @@ -499,8 +499,8 @@ return getParsedDstIndex(); auto SrcIdx = OprIdx - Component::DST_NUM; - if (SrcIdx < getSrcOperandsNum()) - return getParsedSrcIndex(SrcIdx, hasSrc2Acc()); + if (SrcIdx < getParsedSrcOperandsNum()) + return getParsedSrcIndex(SrcIdx); // The specified operand does not exist. return 0; @@ -522,25 +522,30 @@ return {}; } +// Return an array of VGPR registers [DST,SRC0,SRC1,SRC2] used +// by the specified component. If an operand is unused +// or is not a VGPR, the corresponding value is 0. +// +// GetRegIdx(Component, OperandIdx) must return a VGPR register index +// for the specified component and operand. The callback must return 0 +// if the operand is not a register or not a VGPR. InstInfo::RegIndices InstInfo::getRegIndices( unsigned ComponentIdx, std::function GetRegIdx) const { assert(ComponentIdx < COMPONENTS_NUM); auto Comp = CompInfo[ComponentIdx]; + InstInfo::RegIndices RegIndices; - unsigned DstReg = GetRegIdx(ComponentIdx, Comp.getDstIndex()); - unsigned Src0Reg = GetRegIdx(ComponentIdx, Comp.getSrcIndex(0)); - - unsigned Src1Reg = 0; - if (Comp.hasRegularSrcOperand(1)) - Src1Reg = GetRegIdx(ComponentIdx, Comp.getSrcIndex(1)); + RegIndices[DST] = GetRegIdx(ComponentIdx, Comp.getDstIndex()); - unsigned Src2Reg = 0; - if (Comp.hasRegularSrcOperand(2)) - Src2Reg = GetRegIdx(ComponentIdx, Comp.getSrcIndex(2)); - - return {DstReg, Src0Reg, Src1Reg, Src2Reg}; + for (unsigned OprIdx : {SRC0, SRC1, SRC2}) { + unsigned SrcIdx = OprIdx - DST_NUM; + RegIndices[OprIdx] = Comp.hasRegSrcOperand(SrcIdx) + ? GetRegIdx(ComponentIdx, Comp.getSrcIndex(SrcIdx)) + : 0; + } + return RegIndices; } } // namespace VOPD @@ -555,9 +560,7 @@ const auto &OpXDesc = InstrInfo->get(OpX); const auto &OpYDesc = InstrInfo->get(OpY); VOPD::ComponentInfo OpXInfo(OpXDesc, VOPD::ComponentKind::COMPONENT_X); - VOPD::ComponentInfo OpYInfo( - OpYDesc, VOPD::ComponentKind::COMPONENT_Y, OpXInfo.getSrcOperandsNum(), - OpXInfo.getSrcOperandsNum() - OpXInfo.hasSrc2Acc()); + VOPD::ComponentInfo OpYInfo(OpYDesc, OpXInfo); return VOPD::InstInfo(OpXInfo, OpYInfo); } Index: llvm/test/MC/AMDGPU/gfx11_asm_vopd_err.s =================================================================== --- llvm/test/MC/AMDGPU/gfx11_asm_vopd_err.s +++ llvm/test/MC/AMDGPU/gfx11_asm_vopd_err.s @@ -266,7 +266,7 @@ v_dual_fmamk_f32 v6, v1, 0xaf123456, v3 :: v_dual_fmac_f32 v5, v2, v3 // GFX11: error: src2 operands must use different VGPR banks // GFX11-NEXT:{{^}}v_dual_fmamk_f32 v6, v1, 0xaf123456, v3 :: v_dual_fmac_f32 v5, v2, v3 -// GFX11-NEXT:{{^}} ^ +// GFX11-NEXT:{{^}} ^ //===----------------------------------------------------------------------===// // Check invalid VOPD syntax.