-
Notifications
You must be signed in to change notification settings - Fork 13.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[llvm][mc][riscv] MC support of T-Head vector extension (xtheadvector) #84447
base: main
Are you sure you want to change the base?
Conversation
Thank you for submitting a Pull Request (PR) to the LLVM Project! This PR will be automatically labeled and the relevant teams will be If you wish to, you can add reviewers by using the "Reviewers" section on this page. If this is not working for you, it is probably because you do not have write If you have received no comments on your PR for a week, you can request a review If you have further questions, they may be answered by the LLVM GitHub User Guide. You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums. |
@llvm/pr-subscribers-llvm-support @llvm/pr-subscribers-backend-risc-v Author: None (kata-ark) ChangesThis PR adds the following support of the T-Head vector extension:
The t-head vector is very similar to RVV 1.0, according to the t-head vector spec, but all assembler instructions are prefixed with Last week we opened a discussion on discourse, and this PR may answer some questions there. Any comments and suggestions are welcomed and appreciated!! Patch is 614.92 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/84447.diff 48 Files Affected:
diff --git a/llvm/include/llvm/TargetParser/RISCVTargetParser.h b/llvm/include/llvm/TargetParser/RISCVTargetParser.h
index cdd19189f8dc7d..36ec58ea3469c1 100644
--- a/llvm/include/llvm/TargetParser/RISCVTargetParser.h
+++ b/llvm/include/llvm/TargetParser/RISCVTargetParser.h
@@ -69,9 +69,16 @@ inline static bool isValidLMUL(unsigned LMUL, bool Fractional) {
return isPowerOf2_32(LMUL) && LMUL <= 8 && (!Fractional || LMUL != 1);
}
+// Is this a EDIV value that can be encoded into the VTYPE format.
+inline static bool isValidEDIV(unsigned EDIV) {
+ return isPowerOf2_32(EDIV) && EDIV <= 8;
+}
+
unsigned encodeVTYPE(RISCVII::VLMUL VLMUL, unsigned SEW, bool TailAgnostic,
bool MaskAgnostic);
+unsigned encodeXTHeadVTYPE(unsigned SEW, unsigned LMUL, unsigned EDIV);
+
inline static RISCVII::VLMUL getVLMUL(unsigned VType) {
unsigned VLMUL = VType & 0x7;
return static_cast<RISCVII::VLMUL>(VLMUL);
@@ -101,12 +108,19 @@ inline static unsigned getSEW(unsigned VType) {
return decodeVSEW(VSEW);
}
+inline static unsigned encodeEDIV(unsigned EDIV) {
+ assert(isValidEDIV(EDIV) && "Unexpected EDIV value");
+ return Log2_32(EDIV);
+}
+
inline static bool isTailAgnostic(unsigned VType) { return VType & 0x40; }
inline static bool isMaskAgnostic(unsigned VType) { return VType & 0x80; }
void printVType(unsigned VType, raw_ostream &OS);
+void printXTHeadVType(unsigned VType, raw_ostream &OS);
+
unsigned getSEWLMULRatio(unsigned SEW, RISCVII::VLMUL VLMul);
std::optional<RISCVII::VLMUL>
diff --git a/llvm/lib/Support/RISCVISAInfo.cpp b/llvm/lib/Support/RISCVISAInfo.cpp
index 6eec03fd6f7082..f8f8b152c20eca 100644
--- a/llvm/lib/Support/RISCVISAInfo.cpp
+++ b/llvm/lib/Support/RISCVISAInfo.cpp
@@ -106,6 +106,8 @@ static const RISCVSupportedExtension SupportedExtensions[] = {
{"xtheadmempair", {1, 0}},
{"xtheadsync", {1, 0}},
{"xtheadvdot", {1, 0}},
+ {"xtheadvector", {1, 0}},
+ {"xtheadzvamo", {1, 0}},
{"xventanacondops", {1, 0}},
{"za128rs", {1, 0}},
@@ -368,6 +370,18 @@ static StringRef getExtensionType(StringRef Ext) {
return StringRef();
}
+static const RISCVSupportedExtension *
+findExtensionIn(llvm::ArrayRef<RISCVSupportedExtension> ExtensionInfos,
+ StringRef Ext, unsigned MajorVersion, unsigned MinorVersion) {
+ auto Range = std::equal_range(ExtensionInfos.begin(), ExtensionInfos.end(),
+ Ext, LessExtName());
+ for (auto I = Range.first, E = Range.second; I != E; ++I)
+ if (I->Version.Major == MajorVersion && I->Version.Minor == MinorVersion) {
+ return I;
+ }
+ return ExtensionInfos.end();
+}
+
static std::optional<RISCVISAInfo::ExtensionVersion>
isExperimentalExtension(StringRef Ext) {
auto I =
@@ -406,11 +420,8 @@ bool RISCVISAInfo::isSupportedExtension(StringRef Ext, unsigned MajorVersion,
unsigned MinorVersion) {
for (auto ExtInfo : {ArrayRef(SupportedExtensions),
ArrayRef(SupportedExperimentalExtensions)}) {
- auto Range =
- std::equal_range(ExtInfo.begin(), ExtInfo.end(), Ext, LessExtName());
- for (auto I = Range.first, E = Range.second; I != E; ++I)
- if (I->Version.Major == MajorVersion && I->Version.Minor == MinorVersion)
- return true;
+ return findExtensionIn(ExtInfo, Ext, MajorVersion, MinorVersion) !=
+ ExtInfo.end();
}
return false;
@@ -1038,6 +1049,16 @@ Error RISCVISAInfo::checkDependency() {
return createStringError(errc::invalid_argument,
"'zcf' is only supported for 'rv32'");
+ if (Exts.count("xtheadzvamo") && !Exts.count("a"))
+ return createStringError(
+ errc::invalid_argument,
+ "'xtheadzvamo' requires 'a' extension to also be specified");
+
+ if (Exts.count("xtheadvector") && HasVector)
+ return createStringError(
+ errc::invalid_argument,
+ "'xtheadvector' extension is incompatible with 'v' or 'zve*' extension");
+
return Error::success();
}
@@ -1045,6 +1066,7 @@ static const char *ImpliedExtsD[] = {"f"};
static const char *ImpliedExtsF[] = {"zicsr"};
static const char *ImpliedExtsV[] = {"zvl128b", "zve64d"};
static const char *ImpliedExtsXTHeadVdot[] = {"v"};
+static const char *ImpliedExtsXTHeadZvamo[] = {"a"};
static const char *ImpliedExtsXSfvcp[] = {"zve32x"};
static const char *ImpliedExtsXSfvfnrclipxfqf[] = {"zve32f"};
static const char *ImpliedExtsXSfvfwmaccqqq[] = {"zvfbfmin"};
@@ -1125,6 +1147,7 @@ static constexpr ImpliedExtsEntry ImpliedExts[] = {
{{"xsfvqmaccdod"}, {ImpliedExtsXSfvqmaccdod}},
{{"xsfvqmaccqoq"}, {ImpliedExtsXSfvqmaccqoq}},
{{"xtheadvdot"}, {ImpliedExtsXTHeadVdot}},
+ {{"xtheadzvamo"}, {ImpliedExtsXTHeadZvamo}},
{{"zabha"}, {ImpliedExtsZabha}},
{{"zacas"}, {ImpliedExtsZacas}},
{{"zcb"}, {ImpliedExtsZcb}},
diff --git a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
index d83979a873f2a3..32d08cfeafe2cd 100644
--- a/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
+++ b/llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
@@ -163,6 +163,13 @@ class RISCVAsmParser : public MCTargetAsmParser {
// Helper to emit pseudo vmsge{u}.vx instruction.
void emitVMSGE(MCInst &Inst, unsigned Opcode, SMLoc IDLoc, MCStreamer &Out);
+ // Helper to emit pseudo vmsge{u}.vi instruction.
+ void emitVMSGE_VI(MCInst &Inst, unsigned Opcode, unsigned OpcodeImmIs0,
+ SMLoc IDLoc, MCStreamer &Out, bool IsSigned);
+
+ // Helper to emit pseudo vmsge{u}.vx instruction for XTHeadV extension.
+ void emitVMSGE_TH(MCInst &Inst, unsigned Opcode, SMLoc IDLoc, MCStreamer &Out);
+
// Checks that a PseudoAddTPRel is using x4/tp in its second input operand.
// Enforcing this using a restricted register class for the second input
// operand of PseudoAddTPRel results in a poor diagnostic due to the fact
@@ -201,6 +208,7 @@ class RISCVAsmParser : public MCTargetAsmParser {
ParseStatus parsePseudoJumpSymbol(OperandVector &Operands);
ParseStatus parseJALOffset(OperandVector &Operands);
ParseStatus parseVTypeI(OperandVector &Operands);
+ ParseStatus parseXTHeadVTypeI(OperandVector &Operands);
ParseStatus parseMaskReg(OperandVector &Operands);
ParseStatus parseInsnDirectiveOpcode(OperandVector &Operands);
ParseStatus parseInsnCDirectiveOpcode(OperandVector &Operands);
@@ -329,6 +337,7 @@ struct RISCVOperand final : public MCParsedAsmOperand {
FPImmediate,
SystemRegister,
VType,
+ XTHeadVType,
FRM,
Fence,
Rlist,
@@ -422,6 +431,7 @@ struct RISCVOperand final : public MCParsedAsmOperand {
SysReg = o.SysReg;
break;
case KindTy::VType:
+ case KindTy::XTHeadVType:
VType = o.VType;
break;
case KindTy::FRM:
@@ -588,6 +598,11 @@ struct RISCVOperand final : public MCParsedAsmOperand {
return isVTypeImm(11);
return Kind == KindTy::VType;
}
+ bool isXTHeadVTypeI() const {
+ if (Kind == KindTy::Immediate)
+ return isVTypeImm(11);
+ return Kind == KindTy::XTHeadVType;
+ }
/// Return true if the operand is a valid for the fence instruction e.g.
/// ('iorw').
@@ -1002,7 +1017,8 @@ struct RISCVOperand final : public MCParsedAsmOperand {
}
unsigned getVType() const {
- assert(Kind == KindTy::VType && "Invalid type access!");
+ assert((Kind == KindTy::VType || Kind == KindTy::XTHeadVType) &&
+ "Invalid type access!");
return VType.Val;
}
@@ -1044,6 +1060,11 @@ struct RISCVOperand final : public MCParsedAsmOperand {
RISCVVType::printVType(getVType(), OS);
OS << '>';
break;
+ case KindTy::XTHeadVType:
+ OS << "<vtype: ";
+ RISCVVType::printXTHeadVType(getVType(), OS);
+ OS << '>';
+ break;
case KindTy::FRM:
OS << "<frm: ";
roundingModeToString(getFRM());
@@ -1168,6 +1189,14 @@ struct RISCVOperand final : public MCParsedAsmOperand {
return Op;
}
+ static std::unique_ptr<RISCVOperand> createXTHeadVType(unsigned VTypeI, SMLoc S) {
+ auto Op = std::make_unique<RISCVOperand>(KindTy::XTHeadVType);
+ Op->VType.Val = VTypeI;
+ Op->StartLoc = S;
+ Op->EndLoc = S;
+ return Op;
+ }
+
static void addExpr(MCInst &Inst, const MCExpr *Expr, bool IsRV64Imm) {
assert(Expr && "Expr shouldn't be null!");
int64_t Imm = 0;
@@ -1592,6 +1621,13 @@ bool RISCVAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc();
return generateVTypeError(ErrorLoc);
}
+ case Match_InvalidXTHeadVTypeI: {
+ SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc();
+ return Error(
+ ErrorLoc,
+ "operand must be "
+ "e[8|16|32|64|128|256|512|1024],m[1|2|4|8],d[1|2|4|8] for XTHeadVector");
+ }
case Match_InvalidVMaskRegister: {
SMLoc ErrorLoc = ((RISCVOperand &)*Operands[ErrorInfo]).getStartLoc();
return Error(ErrorLoc, "operand must be v0.t");
@@ -2225,6 +2261,57 @@ bool RISCVAsmParser::generateVTypeError(SMLoc ErrorLoc) {
"e[8|16|32|64|128|256|512|1024],m[1|2|4|8|f2|f4|f8],[ta|tu],[ma|mu]");
}
+ParseStatus RISCVAsmParser::parseXTHeadVTypeI(OperandVector &Operands) {
+ SMLoc S = getLoc();
+ if (getLexer().isNot(AsmToken::Identifier))
+ return ParseStatus::NoMatch;
+
+ SmallVector<AsmToken, 7> VTypeIElements;
+ auto MatchFail = [&]() {
+ while (!VTypeIElements.empty())
+ getLexer().UnLex(VTypeIElements.pop_back_val());
+ return ParseStatus::NoMatch;
+ };
+
+ // Put all the tokens for vtypei operand into VTypeIElements vector.
+ while (getLexer().isNot(AsmToken::EndOfStatement)) {
+ VTypeIElements.push_back(getLexer().getTok());
+ getLexer().Lex();
+ if (getLexer().is(AsmToken::EndOfStatement))
+ break;
+ if (getLexer().isNot(AsmToken::Comma))
+ return MatchFail();
+ AsmToken Comma = getLexer().getTok();
+ VTypeIElements.push_back(Comma);
+ getLexer().Lex();
+ }
+
+ if (VTypeIElements.size() == 5) {
+ // The VTypeIElements layout is:
+ // SEW comma LMUL comma EDIV
+ // 0 1 2 3 4
+ StringRef Prefix[] = {"e", "m", "d"};
+ unsigned VTypeEle[3];
+ for (size_t i = 0; i < 3; ++i) {
+ StringRef Name = VTypeIElements[2 * i].getIdentifier();
+ if (!Name.consume_front(Prefix[i]) || Name.getAsInteger(10, VTypeEle[i]))
+ return MatchFail();
+ }
+
+ if (!RISCVVType::isValidSEW(VTypeEle[0]) ||
+ !RISCVVType::isValidLMUL(VTypeEle[1], false) ||
+ !RISCVVType::isValidEDIV(VTypeEle[2]))
+ return MatchFail();
+
+ unsigned VTypeI =
+ RISCVVType::encodeXTHeadVTYPE(VTypeEle[0], VTypeEle[1], VTypeEle[2]);
+ Operands.push_back(RISCVOperand::createXTHeadVType(VTypeI, S));
+ return ParseStatus::Success;
+ }
+
+ return MatchFail();
+}
+
ParseStatus RISCVAsmParser::parseMaskReg(OperandVector &Operands) {
if (getLexer().isNot(AsmToken::Identifier))
return ParseStatus::NoMatch;
@@ -3339,6 +3426,92 @@ void RISCVAsmParser::emitVMSGE(MCInst &Inst, unsigned Opcode, SMLoc IDLoc,
}
}
+
+void RISCVAsmParser::emitVMSGE_VI(MCInst &Inst, unsigned Opcode,
+ unsigned OpcodeImmIs0, SMLoc IDLoc,
+ MCStreamer &Out, bool IsSigned) {
+ int64_t Imm = Inst.getOperand(2).getImm();
+ if (IsSigned) {
+ // These instructions are signed and so is immediate so we can subtract one.
+ emitToStreamer(Out, MCInstBuilder(Opcode)
+ .addOperand(Inst.getOperand(0))
+ .addOperand(Inst.getOperand(1))
+ .addImm(Imm - 1)
+ .addOperand(Inst.getOperand(3)));
+ } else {
+ // Unsigned comparisons are tricky because the immediate is signed. If the
+ // immediate is 0 we can't just subtract one. vmsltu.vi v0, v1, 0 is always
+ // false, but vmsle.vi v0, v1, -1 is always true. Instead we use
+ // vmsne v0, v1, v1 which is always false.
+ if (Imm == 0) {
+ emitToStreamer(Out, MCInstBuilder(OpcodeImmIs0)
+ .addOperand(Inst.getOperand(0))
+ .addOperand(Inst.getOperand(1))
+ .addOperand(Inst.getOperand(1))
+ .addOperand(Inst.getOperand(3)));
+ } else {
+ // Other immediate values can subtract one like signed.
+ emitToStreamer(Out, MCInstBuilder(Opcode)
+ .addOperand(Inst.getOperand(0))
+ .addOperand(Inst.getOperand(1))
+ .addImm(Imm - 1)
+ .addOperand(Inst.getOperand(3)));
+ }
+ }
+}
+
+void RISCVAsmParser::emitVMSGE_TH(MCInst &Inst, unsigned Opcode, SMLoc IDLoc,
+ MCStreamer &Out) {
+ // https://github.com/riscv/riscv-v-spec/releases/tag/0.7.1
+ if (Inst.getNumOperands() == 3) {
+ // unmasked va >= x
+ //
+ // pseudoinstruction: vmsge{u}.vx vd, va, x
+ // expansion: vmslt{u}.vx vd, va, x; vmnand.mm vd, vd, vd
+ emitToStreamer(Out, MCInstBuilder(Opcode)
+ .addOperand(Inst.getOperand(0))
+ .addOperand(Inst.getOperand(1))
+ .addOperand(Inst.getOperand(2))
+ .addReg(RISCV::NoRegister));
+ emitToStreamer(Out, MCInstBuilder(RISCV::TH_VMNAND_MM)
+ .addOperand(Inst.getOperand(0))
+ .addOperand(Inst.getOperand(0))
+ .addOperand(Inst.getOperand(0)));
+ } else if (Inst.getNumOperands() == 4) {
+ // masked va >= x, vd != v0
+ //
+ // pseudoinstruction: vmsge{u}.vx vd, va, x, v0.t
+ // expansion: vmslt{u}.vx vd, va, x, v0.t; vmxor.mm vd, vd, v0
+ assert(Inst.getOperand(0).getReg() != RISCV::V0 &&
+ "The destination register should not be V0.");
+ emitToStreamer(Out, MCInstBuilder(Opcode)
+ .addOperand(Inst.getOperand(0))
+ .addOperand(Inst.getOperand(1))
+ .addOperand(Inst.getOperand(2))
+ .addOperand(Inst.getOperand(3)));
+ emitToStreamer(Out, MCInstBuilder(RISCV::TH_VMXOR_MM)
+ .addOperand(Inst.getOperand(0))
+ .addOperand(Inst.getOperand(0))
+ .addReg(RISCV::V0));
+ } else if (Inst.getNumOperands() == 5) {
+ // masked va >= x, any vd
+ //
+ // pseudoinstruction: vmsge{u}.vx vd, va, x, v0.t, vt
+ // expansion: vmslt{u}.vx vt, va, x; vmandnot.mm vd, vd, vt
+ assert(Inst.getOperand(1).getReg() != RISCV::V0 &&
+ "The temporary vector register should not be V0.");
+ emitToStreamer(Out, MCInstBuilder(Opcode)
+ .addOperand(Inst.getOperand(1))
+ .addOperand(Inst.getOperand(2))
+ .addOperand(Inst.getOperand(3))
+ .addReg(RISCV::NoRegister));
+ emitToStreamer(Out, MCInstBuilder(RISCV::TH_VMANDN_MM)
+ .addOperand(Inst.getOperand(0))
+ .addOperand(Inst.getOperand(0))
+ .addOperand(Inst.getOperand(1)));
+ }
+}
+
bool RISCVAsmParser::checkPseudoAddTPRel(MCInst &Inst,
OperandVector &Operands) {
assert(Inst.getOpcode() == RISCV::PseudoAddTPRel && "Invalid instruction");
@@ -3385,7 +3558,9 @@ bool RISCVAsmParser::validateInstruction(MCInst &Inst,
unsigned Opcode = Inst.getOpcode();
if (Opcode == RISCV::PseudoVMSGEU_VX_M_T ||
- Opcode == RISCV::PseudoVMSGE_VX_M_T) {
+ Opcode == RISCV::PseudoVMSGE_VX_M_T ||
+ Opcode == RISCV::PseudoTH_VMSGEU_VX_M_T ||
+ Opcode == RISCV::PseudoTH_VMSGE_VX_M_T) {
unsigned DestReg = Inst.getOperand(0).getReg();
unsigned TempReg = Inst.getOperand(1).getReg();
if (DestReg == TempReg) {
@@ -3627,49 +3802,40 @@ bool RISCVAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
emitVMSGE(Inst, RISCV::VMSLT_VX, IDLoc, Out);
return false;
case RISCV::PseudoVMSGE_VI:
- case RISCV::PseudoVMSLT_VI: {
- // These instructions are signed and so is immediate so we can subtract one
- // and change the opcode.
- int64_t Imm = Inst.getOperand(2).getImm();
- unsigned Opc = Inst.getOpcode() == RISCV::PseudoVMSGE_VI ? RISCV::VMSGT_VI
- : RISCV::VMSLE_VI;
- emitToStreamer(Out, MCInstBuilder(Opc)
- .addOperand(Inst.getOperand(0))
- .addOperand(Inst.getOperand(1))
- .addImm(Imm - 1)
- .addOperand(Inst.getOperand(3)));
+ emitVMSGE_VI(Inst, RISCV::VMSGT_VI, RISCV::VMSGT_VI, IDLoc, Out, true);
+ return false;
+ case RISCV::PseudoVMSLT_VI:
+ emitVMSGE_VI(Inst, RISCV::VMSLE_VI, RISCV::VMSLE_VI, IDLoc, Out, true);
return false;
- }
case RISCV::PseudoVMSGEU_VI:
- case RISCV::PseudoVMSLTU_VI: {
- int64_t Imm = Inst.getOperand(2).getImm();
- // Unsigned comparisons are tricky because the immediate is signed. If the
- // immediate is 0 we can't just subtract one. vmsltu.vi v0, v1, 0 is always
- // false, but vmsle.vi v0, v1, -1 is always true. Instead we use
- // vmsne v0, v1, v1 which is always false.
- if (Imm == 0) {
- unsigned Opc = Inst.getOpcode() == RISCV::PseudoVMSGEU_VI
- ? RISCV::VMSEQ_VV
- : RISCV::VMSNE_VV;
- emitToStreamer(Out, MCInstBuilder(Opc)
- .addOperand(Inst.getOperand(0))
- .addOperand(Inst.getOperand(1))
- .addOperand(Inst.getOperand(1))
- .addOperand(Inst.getOperand(3)));
- } else {
- // Other immediate values can subtract one like signed.
- unsigned Opc = Inst.getOpcode() == RISCV::PseudoVMSGEU_VI
- ? RISCV::VMSGTU_VI
- : RISCV::VMSLEU_VI;
- emitToStreamer(Out, MCInstBuilder(Opc)
- .addOperand(Inst.getOperand(0))
- .addOperand(Inst.getOperand(1))
- .addImm(Imm - 1)
- .addOperand(Inst.getOperand(3)));
- }
-
+ emitVMSGE_VI(Inst, RISCV::VMSGTU_VI, RISCV::VMSEQ_VV, IDLoc, Out, false);
+ return false;
+ case RISCV::PseudoVMSLTU_VI:
+ emitVMSGE_VI(Inst, RISCV::VMSLEU_VI, RISCV::VMSNE_VV, IDLoc, Out, false);
+ return false;
+ // for XTHeadVector Extension
+ case RISCV::PseudoTH_VMSGEU_VX:
+ case RISCV::PseudoTH_VMSGEU_VX_M:
+ case RISCV::PseudoTH_VMSGEU_VX_M_T:
+ emitVMSGE_TH(Inst, RISCV::TH_VMSLTU_VX, IDLoc, Out);
+ return false;
+ case RISCV::PseudoTH_VMSGE_VX:
+ case RISCV::PseudoTH_VMSGE_VX_M:
+ case RISCV::PseudoTH_VMSGE_VX_M_T:
+ emitVMSGE_TH(Inst, RISCV::TH_VMSLT_VX, IDLoc, Out);
+ return false;
+ case RISCV::PseudoTH_VMSGE_VI:
+ emitVMSGE_VI(Inst, RISCV::TH_VMSGT_VI, RISCV::TH_VMSGT_VI, IDLoc, Out, true);
+ return false;
+ case RISCV::PseudoTH_VMSLT_VI:
+ emitVMSGE_VI(Inst, RISCV::TH_VMSLE_VI, RISCV::TH_VMSLE_VI, IDLoc, Out, true);
+ return false;
+ case RISCV::PseudoTH_VMSGEU_VI:
+ emitVMSGE_VI(Inst, RISCV::TH_VMSGTU_VI, RISCV::TH_VMSEQ_VV, IDLoc, Out, false);
+ return false;
+ case RISCV::PseudoTH_VMSLTU_VI:
+ emitVMSGE_VI(Inst, RISCV::TH_VMSLEU_VI, RISCV::TH_VMSNE_VV, IDLoc, Out, false);
return false;
- }
}
emitToStreamer(Out, Inst);
diff --git a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
index f1ca1212ec378e..656bd5aac47ea5 100644
--- a/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
+++ b/llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
@@ -581,6 +581,8 @@ DecodeStatus RISCVDisassembler::getInstruction(MCInst &MI, uint64_t &Size,
"XTHeadSync custom opcode table");
TRY_TO_DECODE_FEATURE(RISCV::FeatureVendorXTHeadVdot, DecoderTableXTHeadVdot32,
"XTHeadVdot custom opcode table");
+ TRY_T...
[truncated]
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added some T-Head guys to review this.
@@ -106,6 +106,8 @@ static const RISCVSupportedExtension SupportedExtensions[] = { | |||
{"xtheadmempair", {1, 0}}, | |||
{"xtheadsync", {1, 0}}, | |||
{"xtheadvdot", {1, 0}}, | |||
{"xtheadvector", {1, 0}}, | |||
{"xtheadzvamo", {1, 0}}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know if we need this. IIRC, C906/C910 didn't implement this extension. CC @zixuan-wu @rjiejie
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
HI, Pengcheng,
In fact, C906/C910 support the Zvamo
extension related instructions. For details here. As I have already described in the spec, it has only been renamed from Zvamo
to XTheadZvamo
. BTW, Here is a binutils patch that has been tested and reviewed for reference.
@@ -69,9 +69,16 @@ inline static bool isValidLMUL(unsigned LMUL, bool Fractional) { | |||
return isPowerOf2_32(LMUL) && LMUL <= 8 && (!Fractional || LMUL != 1); | |||
} | |||
|
|||
// Is this a EDIV value that can be encoded into the VTYPE format. | |||
inline static bool isValidEDIV(unsigned EDIV) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIRC, C906/C910 didn't implement EDIV.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I also think it should not be implemented because there is no hardware to support it.
for (auto I = Range.first, E = Range.second; I != E; ++I) | ||
if (I->Version.Major == MajorVersion && I->Version.Minor == MinorVersion) | ||
return true; | ||
return findExtensionIn(ExtInfo, Ext, MajorVersion, MinorVersion) != |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change doesn't belong to this PR I think.
Thanks for working on this. I plan to experiment with this on an SG2042 system soon. I also created a PR to rebase this on |
Oh, There's a more complete but draft version with more intrinsics, rather than only MC instructions, on https://github.com/ruyisdk/llvm-project which is based on LLVM 17.0.6 (actually, this PR is "cherry-picked" from that downstream repo). Maybe worth a try? 😉 |
Hi @kata-ark, welcome to the LLVM project and thank you for posting your first PR. I'm afraid I have to raise a pretty important issue here - you note that you've directly ported a gas test case as part of your work. Due to LLVM's copyright and license policy this isn't something that can be accepted due to GNU as source code and tests being under a different license. Please create original MC layer tests that are not adapted/copied from GNU. |
It does help with that, thank you. Given we started discussion there it would probably be best to try to keep discussion around the policy question of taking in patches supporting this extension in that thread, so discussion doesn't get spread out all over the place. I've fed back a question that came up in the last RISC-V LLVM sync-up call there. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See comment re source of test files.
Thanks for your reply. I will delete that test. But I have to clarify that, by "ported" I mean:
I am not sure if decompiling a program that is compiled from a source file licensed under the GPL violates LLVM's copyright and license policy or general GPL rules. But to avoid misunderstanding, I will still delete this test. As the remaining tests can already cover the new assembly instructions very well. The test from GNU AS is added just to ensure the consistency of behavior between LLVM and GCC. |
Okay, let's move the discussion to where it started. 😉 |
// | ||
//===----------------------------------------------------------------------===// | ||
/// | ||
/// This file describes the RISC-V instructions from the standard 'V' Vector |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please clarify this comment is for the T-Head implementation since all instruction names have th.
prefix it is not the standard extension.
def : InstAlias<"th.vmmv.m $vd, $vs", | ||
(TH_VMAND_MM VR:$vd, VR:$vs, VR:$vs), 0>; | ||
def : InstAlias<"th.vneg.v $vd, $vs", | ||
(TH_VRSUB_VX VR:$vd, VR:$vs, X0, zero_reg)>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why no th.vneg.v
alias with VMaskOp:$vm
? We have one for the V extension.
def : InstAlias<"th.vncvt.x.x.v $vd, $vs$vm", | ||
(TH_VNSRL_VX VR:$vd, VR:$vs, X0, VMaskOp:$vm)>; | ||
def : InstAlias<"th.vfneg.v $vd, $vs", | ||
(TH_VFSGNJN_VV VR:$vd, VR:$vs, VR:$vs, zero_reg)>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why no th.vfneg.v
alias with VMaskOp:$vm
? We have one for the V extension.
(TH_VNSRL_VX VR:$vd, VR:$vs, X0, VMaskOp:$vm)>; | ||
def : InstAlias<"th.vfneg.v $vd, $vs", | ||
(TH_VFSGNJN_VV VR:$vd, VR:$vs, VR:$vs, zero_reg)>; | ||
def : InstAlias<"th.vfabs.v $vd, $vs", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why no th.vfabs.v
alias with VMaskOp:$vm
? We have one for the V extension.
let RVVConstraint = NoConstraint in { | ||
defm TH_VMAND_M : VMALU_MV_Mask<"th.vmand", 0b011001, "m">; | ||
defm TH_VMNAND_M : VMALU_MV_Mask<"th.vmnand", 0b011101, "m">; | ||
defm TH_VMANDN_M : VMALU_MV_Mask<"th.vmandnot", 0b011000, "m">; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be TH_VMANDNOT_M to match the mnemonic
let RVVConstraint = NoConstraint in { | ||
let Uses = [FRM], mayRaiseFPException = true in { | ||
defm TH_VFREDOSUM : VREDO_FV_V<"th.vfredosum", 0b000011>; | ||
defm TH_VFREDUSUM : VRED_FV_V<"th.vfredsum", 0b000001>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be TH_VFREDSUM to match the mnemonic
} | ||
|
||
let hasSideEffects = 0, mayLoad = 1, mayStore = 1 in { | ||
// vamo vd, vs2, (rs1), vd, vm |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this syntax only documented in the 0.8 spec and not the 0.7.1 spec?
Super awesome @kata-ark thank you for doing this. I'm sorry for the back and forth on this, but it is very important to LLVM to make sure to protect the rights of people who are innovating and creating things, which means we have to be careful about derivative works. I am very happy you're pushing forward here and are trying to make LLVM better, I'm sorry it cost you a bit of time, but this sort of thing helps make LLVM stronger in the long run. Thank you! |
This PR adds the following support of the T-Head vector extension:
RISCVISAInfo.cpp
.The t-head vector is very similar to RVV 1.0, according to the t-head vector spec, but all assembler instructions are prefixed with
th.
. This PR implements the MC support by creating a new decoder namespace. We are looking for an elegant method to reuse existing instructions fromRISCVInstrInfoV.td
automatically, without adding any TableGen symbol for the "same instructions" (only names are prefixed withth.
) between RVV 1.0 and T-Head Vector.Last week we opened a discussion on discourse, and this PR may answer some questions there. Any comments and suggestions are welcomed and appreciated!!