blob: 25c1d027768af2317fd632916fdb782d8eb97823 [file] [log] [blame]
//===-- VCIX.td - VCIX dialect operation definitions *- tablegen -*--------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// The file defines the basic operations for the VCIX dialect.
//
// The SiFive Vector Coprocessor Interface (VCIX) provides a flexible mechanism
// to extend application processors with custom coprocessors and
// variable-latency arithmetic units. The interface offers throughput comparable
// to that of standard RISC-V vector instructions. To accelerate performance,
// system designers may use VCIX as a low-latency, high-throughput interface to
// a coprocessor
//
// https://www.sifive.com/document-file/sifive-vector-coprocessor-interface-vcix-software
//
//===----------------------------------------------------------------------===//
#ifndef VCIXIR_OPS
include "mlir/IR/OpBase.td"
include "mlir/Dialect/LLVMIR/LLVMOpBase.td"
//===----------------------------------------------------------------------===//
// VCIX dialect definition.
//===----------------------------------------------------------------------===//
def VCIX_Dialect : Dialect {
let name = "vcix";
let cppNamespace = "::mlir::vcix";
let dependentDialects = ["LLVM::LLVMDialect"];
let description = [{
The SiFive Vector Coprocessor Interface (VCIX) provides a flexible mechanism
to extend application processors with custom coprocessors and
variable-latency arithmetic units. The interface offers throughput comparable
to that of standard RISC-V vector instructions. To accelerate performance,
system designers may use VCIX as a low-latency, high-throughput interface to
a coprocessor
https://www.sifive.com/document-file/sifive-vector-coprocessor-interface-vcix-software
}];
}
// Special version for intrinsic version where int attr is zext to i32 or i64
// depending on xlen of the target.
def VCIX_VectorOrScalar
: AnyTypeOf<[LLVM_AnyVector, I<64>, I<32>, F<16>, F<32>, F<64>]>;
def VCIX_OpcodeAttr : AnyAttrOf<[I32Attr, I64Attr]>;
def VCIX_Register : AnyTypeOf<[I32, I64]>;
def VCIX_ImmAttr : AnyAttrOf<[I32Attr, I64Attr]>;
def VCIX_VL : AnyTypeOf<[I<64>, I<32>]>;
class VCIX_Op<string mnemonic, list<Trait> traits = []>
: LLVM_OpBase<VCIX_Dialect, mnemonic, traits> {
}
def VCIX_BinaryImmOp : VCIX_Op<"v.iv">,
Results<(outs LLVM_AnyVector: $res)>,
Arguments<(ins VCIX_OpcodeAttr: $opcode,
LLVM_AnyVector: $vs2,
VCIX_ImmAttr: $imm,
Optional<VCIX_VL>: $vl)> {
let summary = "Binary VCIX operation with an immediate second operand";
let description = [{
Binary VCIX operation with an immediate second operand.
Correponds to:
|Mnemonic|funct6|vm|rs2|rs1|funct3|rd|Destination|Sources|
|--|--|--|--|--|--|--|--|--|
|sf.vc.v.iv|0010--|0|vs2|simm|011|vd|vector vd| simm[4:0] vector vs2|
}];
string llvmBuilder = [{
llvm::Type *xlen =getXlenType($opcode, moduleTranslation);
llvm::Value *opcodeConst = mlir::LLVM::detail::getLLVMConstant(
xlen, $opcode, $_location, moduleTranslation);
llvm::Value *immConst = mlir::LLVM::detail::getLLVMConstant(
xlen, $imm, $_location, moduleTranslation);
VectorType vt = op.getResult().getType().cast<VectorType>();
llvm::Value *vl =
createVL(builder, $vl, vt, xlen, $_location, moduleTranslation);
$res = createIntrinsicCall(
builder, llvm::Intrinsic::riscv_sf_vc_v_iv_se,
{opcodeConst, $vs2, immConst, vl},
{$_resultType, xlen, $vs2->getType(), xlen, xlen});
}];
}
def VCIX_BinaryOp : VCIX_Op<"v.sv">,
Results<(outs LLVM_AnyVector: $res)>,
Arguments<(ins VCIX_OpcodeAttr: $opcode,
LLVM_AnyVector: $vs2,
VCIX_VectorOrScalar: $op,
Optional<VCIX_VL>: $vl)> {
let summary = "Binary VCIX operation";
let description = [{
Binary VCIX operation with an integer scalar, or floating pointer scalar or
vector second operand.
Correponds to:
|Mnemonic|funct6|vm|rs2|rs1|funct3|rd|Destination| Sources|
|--|--|--|--|--|--|--|--|--|--|
|sf.vc.v.vv|0010--|0|vs2|vs1|000|vd|vector vd|vector vs1, vector vs|
|sf.vc.v.xv|0010--|0|vs2|xs1|100|vd|vector vd|scalar xs1, vector vs2|
|sf.vc.v.fv|0010--|0|vs2|fs1|101|vd|vector vd|scalar fs1, vector vs2|
}];
string llvmBuilder = [{
llvm::Type *xlen = getXlenType($opcode, moduleTranslation);
llvm::Value *opcodeConst = mlir::LLVM::detail::getLLVMConstant(
xlen, $opcode, $_location, moduleTranslation);
llvm::Intrinsic::ID id;
llvm::Type *opType = $op->getType();
if (opType->isVectorTy()) {
id = llvm::Intrinsic::riscv_sf_vc_v_vv_se;
} else if (opType->isIntegerTy()) {
id = llvm::Intrinsic::riscv_sf_vc_v_xv_se;
} else {
id = llvm::Intrinsic::riscv_sf_vc_v_fv_se;
}
VectorType vt = op.getResult().getType().cast<VectorType>();
llvm::Value *vl =
createVL(builder, $vl, vt, xlen, $_location, moduleTranslation);
$res = createIntrinsicCall(
builder, id, {opcodeConst, $vs2, $op, vl},
{$_resultType, xlen, $vs2->getType(), $op->getType(), xlen});
}];
}
#endif // VCIXIR_OPS