//===- SPIRVCLOps.td - OpenCL extended insts spec file ----*- 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
//
//===----------------------------------------------------------------------===//
//
// This is the op definition spec of OpenCL extension ops.
//
//===----------------------------------------------------------------------===//

#ifndef MLIR_DIALECT_SPIRV_IR_CL_OPS
#define MLIR_DIALECT_SPIRV_IR_CL_OPS

include "mlir/Dialect/SPIRV/IR/SPIRVBase.td"

//===----------------------------------------------------------------------===//
// SPIR-V OpenCL opcode specification.
//===----------------------------------------------------------------------===//

// Base class for all OpenCL ops.
class SPV_CLOp<string mnemonic, int opcode, list<Trait> traits = []> :
  SPV_ExtInstOp<mnemonic, "CL", "OpenCL.std", opcode, traits> {

  let availability = [
    MinVersion<SPV_V_1_0>,
    MaxVersion<SPV_V_1_5>,
    Extension<[]>,
    Capability<[SPV_C_Kernel]>
  ];
}

// Base class for OpenCL unary ops.
class SPV_CLUnaryOp<string mnemonic, int opcode, Type resultType,
                     Type operandType, list<Trait> traits = []> :
  SPV_CLOp<mnemonic, opcode, !listconcat([NoSideEffect], traits)> {

  let arguments = (ins
    SPV_ScalarOrVectorOf<operandType>:$operand
  );

  let results = (outs
    SPV_ScalarOrVectorOf<resultType>:$result
  );

  let assemblyFormat = "$operand `:` type($operand) attr-dict";

  let hasVerifier = 0;
}

// Base class for OpenCL Unary arithmetic ops where return type matches
// the operand type.
class SPV_CLUnaryArithmeticOp<string mnemonic, int opcode, Type type,
                               list<Trait> traits = []> :
  SPV_CLUnaryOp<mnemonic, opcode, type, type,
                 traits # [SameOperandsAndResultType]>;

// Base class for OpenCL binary ops.
class SPV_CLBinaryOp<string mnemonic, int opcode, Type resultType,
                      Type operandType, list<Trait> traits = []> :
  SPV_CLOp<mnemonic, opcode, !listconcat([NoSideEffect], traits)> {

  let arguments = (ins
    SPV_ScalarOrVectorOf<operandType>:$lhs,
    SPV_ScalarOrVectorOf<operandType>:$rhs
  );

  let results = (outs
    SPV_ScalarOrVectorOf<resultType>:$result
  );

  let hasVerifier = 0;
}

// Base class for OpenCL Binary arithmetic ops where operand types and
// return type matches.
class SPV_CLBinaryArithmeticOp<string mnemonic, int opcode, Type type,
                                list<Trait> traits = []> :
  SPV_CLBinaryOp<mnemonic, opcode, type, type,
                  traits # [SameOperandsAndResultType]> {
  let assemblyFormat = "operands attr-dict `:` type($result)";
}

// Base class for OpenCL binary ops.
class SPV_CLTernaryOp<string mnemonic, int opcode, Type resultType,
                      Type operandType, list<Trait> traits = []> :
  SPV_CLOp<mnemonic, opcode, !listconcat([NoSideEffect], traits)> {

  let arguments = (ins
    SPV_ScalarOrVectorOf<operandType>:$x,
    SPV_ScalarOrVectorOf<operandType>:$y,
    SPV_ScalarOrVectorOf<operandType>:$z
  );

  let results = (outs
    SPV_ScalarOrVectorOf<resultType>:$result
  );

  let hasVerifier = 0;
}

// Base class for OpenCL Ternary arithmetic ops where operand types and
// return type matches.
class SPV_CLTernaryArithmeticOp<string mnemonic, int opcode, Type type,
                                list<Trait> traits = []> :
  SPV_CLTernaryOp<mnemonic, opcode, type, type,
                  traits # [SameOperandsAndResultType]> {
  let assemblyFormat = "operands attr-dict `:` type($result)";
}



// -----

def SPV_CLCeilOp : SPV_CLUnaryArithmeticOp<"ceil", 12, SPV_Float> {
  let summary = [{
    Round x to integral value using the round to positive infinity rounding
    mode.
  }];

  let description = [{
    Result Type and x must be floating-point or vector(2,3,4,8,16) of
    floating-point values.

    All of the operands, including the Result Type operand, must be of the
    same type.

    <!-- End of AutoGen section -->

    ```
    float-scalar-vector-type ::= float-type |
                                 `vector<` integer-literal `x` float-type `>`
    ceil-op ::= ssa-id `=` `spv.CL.ceil` ssa-use `:`
               float-scalar-vector-type
    ```mlir

    #### Example:

    ```
    %2 = spv.CL.ceil %0 : f32
    %3 = spv.CL.ceil %1 : vector<3xf16>
    ```
  }];
}

// -----

def SPV_CLCosOp : SPV_CLUnaryArithmeticOp<"cos", 14, SPV_Float> {
  let summary = "Compute the cosine of x radians.";

  let description = [{
    Result Type and x must be floating-point or vector(2,3,4,8,16) of
    floating-point values.

    All of the operands, including the Result Type operand, must be of the
    same type.

    <!-- End of AutoGen section -->

    ```
    float-scalar-vector-type ::= float-type |
                                 `vector<` integer-literal `x` float-type `>`
    cos-op ::= ssa-id `=` `spv.CL.cos` ssa-use `:`
               float-scalar-vector-type
    ```mlir

    #### Example:

    ```
    %2 = spv.CL.cos %0 : f32
    %3 = spv.CL.cos %1 : vector<3xf16>
    ```
  }];
}

// -----

def SPV_CLErfOp : SPV_CLUnaryArithmeticOp<"erf", 18, SPV_Float> {
  let summary = [{
    Error function of x encountered in integrating the normal distribution.
  }];

  let description = [{
    Result Type and x must be floating-point or vector(2,3,4,8,16) of
    floating-point values.

    All of the operands, including the Result Type operand, must be of the
    same type.

    <!-- End of AutoGen section -->

    ```
    float-scalar-vector-type ::= float-type |
                                 `vector<` integer-literal `x` float-type `>`
    erf-op ::= ssa-id `=` `spv.CL.erf` ssa-use `:`
               float-scalar-vector-type
    ```mlir

    #### Example:

    ```
    %2 = spv.CL.erf %0 : f32
    %3 = spv.CL.erf %1 : vector<3xf16>
    ```
  }];
}

// -----

def SPV_CLExpOp : SPV_CLUnaryArithmeticOp<"exp", 19, SPV_Float> {
  let summary = "Exponentiation of Operand 1";

  let description = [{
    Compute the base-e exponential of x. (i.e. ex)

    Result Type and x must be floating-point or vector(2,3,4,8,16) of
    floating-point values.

    All of the operands, including the Result Type operand,
    must be of the same type.

    <!-- End of AutoGen section -->
    ```
    float-scalar-vector-type ::= float-type |
                                 `vector<` integer-literal `x` float-type `>`
    exp-op ::= ssa-id `=` `spv.CL.exp` ssa-use `:`
               float-scalar-vector-type
    ```
    #### Example:

    ```mlir
    %2 = spv.CL.exp %0 : f32
    %3 = spv.CL.exp %1 : vector<3xf16>
    ```
  }];
}

// -----

def SPV_CLFAbsOp : SPV_CLUnaryArithmeticOp<"fabs", 23, SPV_Float> {
  let summary = "Absolute value of operand";

  let description = [{
    Compute the absolute value of x.

    Result Type and x must be floating-point or vector(2,3,4,8,16) of
    floating-point values.

    All of the operands, including the Result Type operand,
    must be of the same type.

    <!-- End of AutoGen section -->
    ```
    float-scalar-vector-type ::= float-type |
                                 `vector<` integer-literal `x` float-type `>`
    abs-op ::= ssa-id `=` `spv.CL.fabs` ssa-use `:`
               float-scalar-vector-type
    ```
    #### Example:

    ```mlir
    %2 = spv.CL.fabs %0 : f32
    %3 = spv.CL.fabs %1 : vector<3xf16>
    ```
  }];
}

// -----

def SPV_CLFloorOp : SPV_CLUnaryArithmeticOp<"floor", 25, SPV_Float> {
  let summary = [{
    Round x to the integral value using the round to negative infinity
    rounding mode.
  }];

  let description = [{
    Result Type and x must be floating-point or vector(2,3,4,8,16) of
    floating-point values.

    All of the operands, including the Result Type operand, must be of the
    same type.

    <!-- End of AutoGen section -->

    ```
    float-scalar-vector-type ::= float-type |
                                 `vector<` integer-literal `x` float-type `>`
    floor-op ::= ssa-id `=` `spv.CL.floor` ssa-use `:`
               float-scalar-vector-type
    ```mlir

    #### Example:

    ```
    %2 = spv.CL.floor %0 : f32
    %3 = spv.CL.ceifloorl %1 : vector<3xf16>
    ```
  }];
}

// -----

def SPV_CLFmaOp : SPV_CLTernaryArithmeticOp<"fma", 26, SPV_Float> {
  let summary = [{
    Compute the correctly rounded floating-point representation of the sum
    of c with the infinitely precise product of a and b. Rounding of
    intermediate products shall not occur. Edge case results are per the
    IEEE 754-2008 standard.
  }];

  let description = [{
    Result Type, a, b and c must be floating-point or vector(2,3,4,8,16) of
    floating-point values.

    All of the operands, including the Result Type operand, must be of the
    same type.

    <!-- End of AutoGen section -->

    ```
    fma-op ::= ssa-id `=` `spv.CL.fma` ssa-use, ssa-use, ssa-use `:`
               float-scalar-vector-type
    ```mlir

    ```
    %0 = spv.CL.fma %a, %b, %c : f32
    %1 = spv.CL.fma %a, %b, %c : vector<3xf16>
    ```
  }];
}

// -----

def SPV_CLLogOp : SPV_CLUnaryArithmeticOp<"log", 37, SPV_Float> {
  let summary = "Compute the natural logarithm of x.";

  let description = [{
    Result Type and x must be floating-point or vector(2,3,4,8,16) of
    floating-point values.

    All of the operands, including the Result Type operand, must be of the
    same type.

    <!-- End of AutoGen section -->

    ```
    float-scalar-vector-type ::= float-type |
                                 `vector<` integer-literal `x` float-type `>`
    log-op ::= ssa-id `=` `spv.CL.log` ssa-use `:`
               float-scalar-vector-type
    ```mlir

    #### Example:

    ```
    %2 = spv.CL.log %0 : f32
    %3 = spv.CL.log %1 : vector<3xf16>
    ```
  }];
}

// -----

def SPV_CLPowOp : SPV_CLBinaryArithmeticOp<"pow", 48, SPV_Float> {
  let summary = "Compute x to the power y.";

  let description = [{
    Result Type, x and y must be floating-point or vector(2,3,4,8,16) of
    floating-point values.

    All of the operands, including the Result Type operand, must be of the
    same type.

    <!-- End of AutoGen section -->

    ```
    restricted-float-scalar-type ::=  `f16` | `f32`
    restricted-float-scalar-vector-type ::=
      restricted-float-scalar-type |
      `vector<` integer-literal `x` restricted-float-scalar-type `>`
    pow-op ::= ssa-id `=` `spv.CL.pow` ssa-use `:`
               restricted-float-scalar-vector-type
    ```
    #### Example:

    ```mlir
    %2 = spv.CL.pow %0, %1 : f32
    %3 = spv.CL.pow %0, %1 : vector<3xf16>
    ```
  }];
}

// -----

def SPV_CLRoundOp : SPV_CLUnaryArithmeticOp<"round", 55, SPV_Float> {
  let summary = [{
    Return the integral value nearest to x rounding halfway cases away from
    zero, regardless of the current rounding direction.
  }];

  let description = [{
    Result Type and x must be floating-point or vector(2,3,4,8,16) of
    floating-point values.

    All of the operands, including the Result Type operand, must be of the
    same type.

    <!-- End of AutoGen section -->

    ```
    float-scalar-vector-type ::= float-type |
                                 `vector<` integer-literal `x` float-type `>`
    round-op ::= ssa-id `=` `spv.CL.round` ssa-use `:`
               float-scalar-vector-type
    ```
    #### Example:

    ```mlir
    %2 = spv.CL.round %0 : f32
    %3 = spv.CL.round %0 : vector<3xf16>
    ```
  }];
}

// -----

def SPV_CLRsqrtOp : SPV_CLUnaryArithmeticOp<"rsqrt", 56, SPV_Float> {
  let summary = "Compute inverse square root of x.";

  let description = [{
    Result Type and x must be floating-point or vector(2,3,4,8,16) of
    floating-point values.

    All of the operands, including the Result Type operand, must be of the
    same type.

    <!-- End of AutoGen section -->

    ```
    float-scalar-vector-type ::= float-type |
                                 `vector<` integer-literal `x` float-type `>`
    rsqrt-op ::= ssa-id `=` `spv.CL.rsqrt` ssa-use `:`
               float-scalar-vector-type
    ```mlir

    #### Example:

    ```
    %2 = spv.CL.rsqrt %0 : f32
    %3 = spv.CL.rsqrt %1 : vector<3xf16>
    ```
  }];
}

// -----

def SPV_CLSinOp : SPV_CLUnaryArithmeticOp<"sin", 57, SPV_Float> {
  let summary = "Compute sine of x radians.";

  let description = [{
    Result Type and x must be floating-point or vector(2,3,4,8,16) of
    floating-point values.

    All of the operands, including the Result Type operand, must be of the
    same type.

    <!-- End of AutoGen section -->

    ```
    float-scalar-vector-type ::= float-type |
                                 `vector<` integer-literal `x` float-type `>`
    sin-op ::= ssa-id `=` `spv.CL.sin` ssa-use `:`
               float-scalar-vector-type
    ```mlir

    #### Example:

    ```
    %2 = spv.CL.sin %0 : f32
    %3 = spv.CL.sin %1 : vector<3xf16>
    ```
  }];
}

// -----

def SPV_CLSqrtOp : SPV_CLUnaryArithmeticOp<"sqrt", 61, SPV_Float> {
  let summary = "Compute square root of x.";

  let description = [{
    Result Type and x must be floating-point or vector(2,3,4,8,16) of
    floating-point values.

    All of the operands, including the Result Type operand, must be of the
    same type.

    <!-- End of AutoGen section -->

    ```
    float-scalar-vector-type ::= float-type |
                                 `vector<` integer-literal `x` float-type `>`
    sqrt-op ::= ssa-id `=` `spv.CL.sqrt` ssa-use `:`
               float-scalar-vector-type
    ```mlir

    #### Example:

    ```
    %2 = spv.CL.sqrt %0 : f32
    %3 = spv.CL.sqrt %1 : vector<3xf16>
    ```
  }];
}

// -----

def SPV_CLTanhOp : SPV_CLUnaryArithmeticOp<"tanh", 63, SPV_Float> {
  let summary = "Compute hyperbolic tangent of x radians.";

  let description = [{
    Result Type and x must be floating-point or vector(2,3,4,8,16) of
    floating-point values.

    All of the operands, including the Result Type operand, must be of the
    same type.

    <!-- End of AutoGen section -->

    ```
    float-scalar-vector-type ::= float-type |
                                 `vector<` integer-literal `x` float-type `>`
    tanh-op ::= ssa-id `=` `spv.CL.tanh` ssa-use `:`
               float-scalar-vector-type
    ```mlir

    #### Example:

    ```
    %2 = spv.CL.tanh %0 : f32
    %3 = spv.CL.tanh %1 : vector<3xf16>
    ```
  }];
}

// -----

def SPV_CLSAbsOp : SPV_CLUnaryArithmeticOp<"s_abs", 141, SPV_Integer> {
  let summary = "Absolute value of operand";

  let description = [{
    Returns |x|, where x is treated as signed integer.

    Result Type and x must be integer or vector(2,3,4,8,16) of
    integer values.

    All of the operands, including the Result Type operand,
    must be of the same type.

    <!-- End of AutoGen section -->
    ```
    integer-scalar-vector-type ::= integer-type |
                                   `vector<` integer-literal `x` integer-type `>`
    abs-op ::= ssa-id `=` `spv.CL.s_abs` ssa-use `:`
               integer-scalar-vector-type
    ```
    #### Example:

    ```mlir
    %2 = spv.CL.s_abs %0 : i32
    %3 = spv.CL.s_abs %1 : vector<3xi16>
    ```
  }];
}

#endif // MLIR_DIALECT_SPIRV_IR_CL_OPS
