Skip to content
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

[RISCV] Add MC layer support for XSfmm*. #133031

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions clang/test/Driver/print-supported-extensions-riscv.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,18 @@
// CHECK-NEXT: xmipscmove 1.0 'XMIPSCMove' (MIPS conditional move instruction(s) (ccmov))
// CHECK-NEXT: xmipslsp 1.0 'XMIPSLSP' (MIPS optimization for hardware load-store bonding)
// CHECK-NEXT: xsfcease 1.0 'XSfcease' (SiFive sf.cease Instruction)
// CHECK-NEXT: xsfmm128t 0.6 'XSfmm128t' (TE=128 configuration)
// CHECK-NEXT: xsfmm16t 0.6 'XSfmm16t' (TE=16 configuration)
// CHECK-NEXT: xsfmm32a 0.6 'XSfmm32a' (TEW=32-bit accumulation, operands - int: 8b; float: fp16, bf16, fp32)
// CHECK-NEXT: xsfmm32a16f 0.6 'XSfmm32a16f' (TEW=32-bit accumulation, operands - float: 16b, widen=2 (IEEE, BF))
// CHECK-NEXT: xsfmm32a32f 0.6 'XSfmm32a32f' (TEW=32-bit accumulation, operands - float: 32b)
// CHECK-NEXT: xsfmm32a4i 0.6 'XSfmm32a4i' (TEW=32-bit accumulation, operands - int: 4b (packed))
// CHECK-NEXT: xsfmm32a8f 0.6 'XSfmm32a8f' (TEW=32-bit accumulation, operands - float: fp8)
// CHECK-NEXT: xsfmm32a8i 0.6 'XSfmm32a8i' (TEW=32-bit accumulation, operands - int: 8b)
// CHECK-NEXT: xsfmm32t 0.6 'XSfmm32t' (TE=32 configuration)
// CHECK-NEXT: xsfmm64a64f 0.6 'XSfmm64a64f' (TEW=64-bit accumulation, operands - float: fp64)
// CHECK-NEXT: xsfmm64t 0.6 'XSfmm64t' (TE=64 configuration)
// CHECK-NEXT: xsfmmbase 0.6 'XSfmmbase' (All non arithmetic instructions for all TEWs and sf.vtzero)
// CHECK-NEXT: xsfvcp 1.0 'XSfvcp' (SiFive Custom Vector Coprocessor Interface Instructions)
// CHECK-NEXT: xsfvfnrclipxfqf 1.0 'XSfvfnrclipxfqf' (SiFive FP32-to-int8 Ranged Clip Instructions)
// CHECK-NEXT: xsfvfwmaccqqq 1.0 'XSfvfwmaccqqq' (SiFive Matrix Multiply Accumulate Instruction and 4-by-4))
Expand Down
95 changes: 95 additions & 0 deletions clang/test/Preprocessor/riscv-target-features-sifive.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// RUN: %clang --target=riscv32 \
// RUN: -march=rv32i_zve32x_xsfmm128t -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-XSFMM128T %s
// RUN: %clang --target=riscv64 \
// RUN: -march=rv64i_zve32x_xsfmm128t -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-XSFMM128T %s
// CHECK-XSFMM128T: __riscv_xsfmm128t 6000{{$}}
//
// RUN: %clang --target=riscv32 \
// RUN: -march=rv32i_zve32x_xsfmm16t -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-XSFMM16T %s
// RUN: %clang --target=riscv64 \
// RUN: -march=rv64i_zve32x_xsfmm16t -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-XSFMM16T %s
// CHECK-XSFMM16T: __riscv_xsfmm16t 6000{{$}}

// RUN: %clang --target=riscv32 \
// RUN: -march=rv32i_zve32x_xsfmm32a -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-XSFMM32A %s
// RUN: %clang --target=riscv64 \
// RUN: -march=rv64i_zve32x_xsfmm32a -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-XSFMM32A %s
// CHECK-XSFMM32A: __riscv_xsfmm32a 6000{{$}}

// RUN: %clang --target=riscv32 \
// RUN: -march=rv32i_zve32x_xsfmm32a4i -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-XSFMM32A4I %s
// RUN: %clang --target=riscv64 \
// RUN: -march=rv64i_zve32x_xsfmm32a4i -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-XSFMM32A4I %s
// CHECK-XSFMM32A4I: __riscv_xsfmm32a4i 6000{{$}}

// RUN: %clang --target=riscv32 \
// RUN: -march=rv32i_zve32x_xsfmm32a8i -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-XSFMM32a8I %s
// RUN: %clang --target=riscv64 \
// RUN: -march=rv64i_zve32x_xsfmm32a8i -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-XSFMM32a8I %s
// CHECK-XSFMM32a8I: __riscv_xsfmm32a8i 6000{{$}}

// RUN: %clang --target=riscv32 \
// RUN: -march=rv32i_zve32x_xsfmm32a8f -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-XSFMM32A8F %s
// RUN: %clang --target=riscv64 \
// RUN: -march=rv64i_zve32x_xsfmm32a8f -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-XSFMM32A8F %s
// CHECK-XSFMM32A8F: __riscv_xsfmm32a8f 6000{{$}}

// RUN: %clang --target=riscv32 \
// RUN: -march=rv32i_zve32x_xsfmm32a16f -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-XSFMM32a16F %s
// RUN: %clang --target=riscv64 \
// RUN: -march=rv64i_zve32x_xsfmm32a16f -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-XSFMM32a16F %s
// CHECK-XSFMM32a16F: __riscv_xsfmm32a16f 6000{{$}}

// RUN: %clang --target=riscv32 \
// RUN: -march=rv32i_zve32x_xsfmm32a32f -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-XSFMM32a32F %s
// RUN: %clang --target=riscv64 \
// RUN: -march=rv64i_zve32x_xsfmm32a32f -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-XSFMM32a32F %s
// CHECK-XSFMM32a32F: __riscv_xsfmm32a32f 6000{{$}}

// RUN: %clang --target=riscv32 \
// RUN: -march=rv32i_zve32x_xsfmm32t -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-XSFMM32T %s
// RUN: %clang --target=riscv64 \
// RUN: -march=rv64i_zve32x_xsfmm32t -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-XSFMM32T %s
// CHECK-XSFMM32T: __riscv_xsfmm32t 6000{{$}}

// RUN: %clang --target=riscv32 \
// RUN: -march=rv32i_zve32x_xsfmm64a64f -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-XSFMM64a64f %s
// RUN: %clang --target=riscv64 \
// RUN: -march=rv64i_zve32x_xsfmm64a64f -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-XSFMM64a64f %s
// CHECK-XSFMM64a64f: __riscv_xsfmm64a64f 6000{{$}}

// RUN: %clang --target=riscv32 \
// RUN: -march=rv32i_zve32x_xsfmm64t -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-XSFMM64T %s
// RUN: %clang --target=riscv64 \
// RUN: -march=rv64i_zve32x_xsfmm64t -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-XSFMM64T %s
// CHECK-XSFMM64T: __riscv_xsfmm64t 6000{{$}}

// RUN: %clang --target=riscv32 \
// RUN: -march=rv32i_zve32x_xsfmmbase -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-XSFMMBASE %s
// RUN: %clang --target=riscv64 \
// RUN: -march=rv64i_zve32x_xsfmmbase -E -dM %s \
// RUN: -o - | FileCheck --check-prefix=CHECK-XSFMMBASE %s
// CHECK-XSFMMBASE: __riscv_xsfmmbase 6000{{$}}
3 changes: 3 additions & 0 deletions llvm/docs/RISCVUsage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,9 @@ The current vendor extensions supported are:
``XVentanaCondOps``
LLVM implements `version 1.0.0 of the VTx-family custom instructions specification <https://github.com/ventanamicro/ventana-custom-extensions/releases/download/v1.0.0/ventana-custom-extensions-v1.0.0.pdf>`__ by Ventana Micro Systems. All instructions are prefixed with `vt.` as described in the specification, and the riscv-toolchain-convention document linked above. These instructions are only available for riscv64 at this time.

``Xsfmm*``
LLVM implements `version 0.6 of the Xsfmm Family of Attached Matrix Extensions Specification <https://www.sifive.com/document-file/xsfmm-matrix-extensions-specification>`__ by SiFive. All instructions are prefixed with `sf.` as described in the specification.

``XSfvcp``
LLVM implements `version 1.1.0 of the SiFive Vector Coprocessor Interface (VCIX) Software Specification <https://sifive.cdn.prismic.io/sifive/Zn3m1R5LeNNTwnLS_vcix-spec-software-v1p1.pdf>`__ by SiFive. All instructions are prefixed with `sf.vc.` as described in the specification, and the riscv-toolchain-convention document linked above.

Expand Down
2 changes: 2 additions & 0 deletions llvm/docs/ReleaseNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ Changes to the RISC-V Backend
* Adds assembler support for ``.option exact``, which disables automatic compression,
and branch and linker relaxation. This can be disabled with ``.option noexact``,
which is also the default.
* Adds experimental assembler support for the SiFive Xsfmm* Attached Matrix
Extensions.

Changes to the WebAssembly Backend
----------------------------------
Expand Down
26 changes: 26 additions & 0 deletions llvm/include/llvm/TargetParser/RISCVTargetParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ inline static bool isValidLMUL(unsigned LMUL, bool Fractional) {
unsigned encodeVTYPE(VLMUL VLMUL, unsigned SEW, bool TailAgnostic,
bool MaskAgnostic);

unsigned encodeXSfmmVType(unsigned SEW, unsigned Widen, bool AltFmt);

inline static VLMUL getVLMUL(unsigned VType) {
unsigned VLMul = VType & 0x7;
return static_cast<VLMUL>(VLMul);
Expand Down Expand Up @@ -126,10 +128,34 @@ inline static unsigned getSEW(unsigned VType) {
return decodeVSEW(VSEW);
}

inline static unsigned decodeTWiden(unsigned TWiden) {
assert((TWiden == 1 || TWiden == 2 || TWiden == 3) &&
"Unexpected TWiden value");
return 1 << (TWiden - 1);
}

inline static bool hasXSfmmWiden(unsigned VType) {
unsigned TWiden = (VType >> 9) & 0x3;
return TWiden != 0;
}

inline static unsigned getXSfmmWiden(unsigned VType) {
unsigned TWiden = (VType >> 9) & 0x3;
assert(TWiden != 0 && "Invalid widen value");
return 1 << (TWiden - 1);
}

static inline bool isValidXSfmmVType(unsigned VTypeI) {
return (VTypeI & ~0x738) == 0 && RISCVVType::hasXSfmmWiden(VTypeI) &&
RISCVVType::getSEW(VTypeI) * RISCVVType::getXSfmmWiden(VTypeI) <= 64;
}

inline static bool isTailAgnostic(unsigned VType) { return VType & 0x40; }

inline static bool isMaskAgnostic(unsigned VType) { return VType & 0x80; }

inline static bool isAltFmt(unsigned VType) { return VType & 0x100; }

void printVType(unsigned VType, raw_ostream &OS);

unsigned getSEWLMULRatio(unsigned SEW, VLMUL VLMul);
Expand Down
89 changes: 89 additions & 0 deletions llvm/lib/Target/RISCV/AsmParser/RISCVAsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ class RISCVAsmParser : public MCTargetAsmParser {
VTypeState_Done,
};

enum WWEEState {
WWEEState_Widen,
WWEEState_SEW,
WWEEState_Done,
};

SmallVector<FeatureBitset, 4> FeatureBitStack;

SmallVector<ParserOptionsSet, 4> ParserOptionsStack;
Expand Down Expand Up @@ -125,6 +131,9 @@ class RISCVAsmParser : public MCTargetAsmParser {
bool &MaskAgnostic);
bool generateVTypeError(SMLoc ErrorLoc);

bool parseXSfmmVTypeToken(const AsmToken &Tok, WWEEState &State, unsigned &WW,
unsigned &EE, bool &AltFmt);
bool generateXSfmmVTypeError(SMLoc ErrorLoc);
// Helper to actually emit an instruction to the MCStreamer. Also, when
// possible, compression of the instruction is performed.
void emitToStreamer(MCStreamer &S, const MCInst &Inst);
Expand Down Expand Up @@ -224,6 +233,7 @@ class RISCVAsmParser : public MCTargetAsmParser {
ParseStatus parseRegListCommon(OperandVector &Operands, bool MustIncludeS0);

ParseStatus parseRegReg(OperandVector &Operands);
ParseStatus parseXSfmmVType(OperandVector &Operands);
ParseStatus parseRetval(OperandVector &Operands);
ParseStatus parseZcmpStackAdj(OperandVector &Operands,
bool ExpectNegative = false);
Expand Down Expand Up @@ -623,6 +633,10 @@ struct RISCVOperand final : public MCParsedAsmOperand {
return isUImm<11>();
}

bool isXSfmmVType() const {
return Kind == KindTy::VType && RISCVVType::isValidXSfmmVType(VType.Val);
}

/// Return true if the operand is a valid for the fence instruction e.g.
/// ('iorw').
bool isFenceArg() const { return Kind == KindTy::Fence; }
Expand Down Expand Up @@ -2269,6 +2283,81 @@ bool RISCVAsmParser::generateVTypeError(SMLoc ErrorLoc) {
"e[8|16|32|64],m[1|2|4|8|f2|f4|f8],[ta|tu],[ma|mu]");
}

bool RISCVAsmParser::parseXSfmmVTypeToken(const AsmToken &Tok, WWEEState &State,
unsigned &WW, unsigned &EE,
bool &AltFmt) {
if (getLexer().isNot(AsmToken::Identifier))
return true;

StringRef Identifier = getTok().getIdentifier();

switch (State) {
case WWEEState_SEW:
if (!Identifier.consume_front("e"))
break;
if (Identifier.getAsInteger(10, EE)) {
if (Identifier != "16alt")
break;

AltFmt = true;
EE = 16;
}
if (!RISCVVType::isValidSEW(EE))
break;
State = WWEEState_Widen;
return false;
case WWEEState_Widen:
if (!Identifier.consume_front("w"))
break;
if (Identifier.getAsInteger(10, WW))
break;
if (WW != 1 && WW != 2 && WW != 4)
break;
State = WWEEState_Done;
return false;
case WWEEState_Done:
// Extra token?
break;
}

return true;
}

ParseStatus RISCVAsmParser::parseXSfmmVType(OperandVector &Operands) {
SMLoc S = getLoc();

unsigned Widen = 0;
unsigned SEW = 0;
bool AltFmt = false;

WWEEState State = WWEEState_SEW;

if (parseXSfmmVTypeToken(getTok(), State, Widen, SEW, AltFmt))
return generateXSfmmVTypeError(S);

getLexer().Lex();

if (!parseOptionalToken(AsmToken::Comma))
return generateXSfmmVTypeError(S);

if (parseXSfmmVTypeToken(getTok(), State, Widen, SEW, AltFmt))
return generateXSfmmVTypeError(S);

getLexer().Lex();

if (getLexer().is(AsmToken::EndOfStatement) && State == WWEEState_Done) {
Operands.push_back(RISCVOperand::createVType(
RISCVVType::encodeXSfmmVType(SEW, Widen, AltFmt), S));
return ParseStatus::Success;
}

return generateXSfmmVTypeError(S);
}

bool RISCVAsmParser::generateXSfmmVTypeError(SMLoc ErrorLoc) {
return Error(ErrorLoc, "operand must be e[8|16|16alt|32|64],w[1|2|4]");
}

ParseStatus RISCVAsmParser::parseMaskReg(OperandVector &Operands) {
if (getLexer().isNot(AsmToken::Identifier))
return ParseStatus::NoMatch;
Expand Down
34 changes: 34 additions & 0 deletions llvm/lib/Target/RISCV/Disassembler/RISCVDisassembler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,39 @@ static DecodeStatus DecodeVMV0RegisterClass(MCInst &Inst, uint32_t RegNo,
return MCDisassembler::Success;
}

static DecodeStatus DecodeTRRegisterClass(MCInst &Inst, uint32_t RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
if (RegNo > 15)
return MCDisassembler::Fail;

MCRegister Reg = RISCV::T0 + RegNo;
Inst.addOperand(MCOperand::createReg(Reg));
return MCDisassembler::Success;
}

static DecodeStatus DecodeTRM2RegisterClass(MCInst &Inst, uint32_t RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
if (RegNo > 15 || RegNo % 2)
return MCDisassembler::Fail;

MCRegister Reg = RISCV::T0 + RegNo;
Inst.addOperand(MCOperand::createReg(Reg));
return MCDisassembler::Success;
}

static DecodeStatus DecodeTRM4RegisterClass(MCInst &Inst, uint32_t RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
if (RegNo > 15 || RegNo % 4)
return MCDisassembler::Fail;

MCRegister Reg = RISCV::T0 + RegNo;
Inst.addOperand(MCOperand::createReg(Reg));
return MCDisassembler::Success;
}

static DecodeStatus decodeVMaskReg(MCInst &Inst, uint32_t RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
Expand Down Expand Up @@ -707,6 +740,7 @@ static constexpr DecoderListEntry DecoderList32[]{
"XVentanaCondOps"},
{DecoderTableXTHead32, XTHeadGroup, "T-Head extensions"},
{DecoderTableXSfvector32, XSfVectorGroup, "SiFive vector extensions"},
{DecoderTableXSfmm32, {RISCV::FeatureVendorXSfmmbase}, "SiFive XSfmm"},
{DecoderTableXSfsystem32, XSfSystemGroup, "SiFive system extensions"},
{DecoderTableXSfcease32, {RISCV::FeatureVendorXSfcease}, "SiFive sf.cease"},
{DecoderTableXmipslsp32, {RISCV::FeatureVendorXMIPSLSP}, "MIPS mips.lsp"},
Expand Down
14 changes: 14 additions & 0 deletions llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,20 @@ void RISCVInstPrinter::printVTypeI(const MCInst *MI, unsigned OpNo,
RISCVVType::printVType(Imm, O);
}

void RISCVInstPrinter::printXSfmmVType(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI,
raw_ostream &O) {
unsigned Imm = MI->getOperand(OpNo).getImm();
assert(RISCVVType::isValidXSfmmVType(Imm));
unsigned SEW = RISCVVType::getSEW(Imm);
O << "e" << SEW;
bool AltFmt = RISCVVType::isAltFmt(Imm);
if (AltFmt)
O << "alt";
unsigned Widen = RISCVVType::getXSfmmWiden(Imm);
O << ", w" << Widen;
}

// Print a Zcmp RList. If we are printing architectural register names rather
// than ABI register names, we need to print "{x1, x8-x9, x18-x27}" for all
// registers. Otherwise, we print "{ra, s0-s11}".
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Target/RISCV/MCTargetDesc/RISCVInstPrinter.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ class RISCVInstPrinter : public MCInstPrinter {
const MCSubtargetInfo &STI, raw_ostream &O);
void printVTypeI(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
raw_ostream &O);
void printXSfmmVType(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI, raw_ostream &O);
void printVMaskReg(const MCInst *MI, unsigned OpNo,
const MCSubtargetInfo &STI, raw_ostream &O);
void printRlist(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
Expand Down
Loading