llvm/mlir/include/mlir/Dialect/LLVMIR/VCIXOps.td

//===-- 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 = mlir::cast<VectorType>(op.getResult().getType());
      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 = mlir::cast<VectorType>(op.getResult().getType());
      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