//
// SPDX-FileCopyrightText: Copyright 2023-2025 Arm Limited and/or its affiliates <open-source-office@arm.com>
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the License); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an AS IS BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Partially generated by tosaValidationGenerator for TOSA Specification 1.0.0draft
// TODO: Implement the constraints.

#include "tosa_error_checks.hpp"

#include "common/ordered_map.hpp"
#include "compiler/attributes.hpp"
#include "compiler/graph.hpp"
#include "compiler/operation.hpp"
#include "compiler/operation_util.hpp"

using regor::DataType;
using regor::Operation;
using regor::ordered_map;
using regor::Scalar;
using regor::Tensor;
using regor::TensorConnection;
using regor::TensorUsage;

static bool shapeCheck(const TensorConnection *t1, int index1, const TensorConnection *t2, int index2)
{
    const auto &shape1 = t1->shape;
    const auto &shape2 = t2->shape;
    if ( index1 < 0 ) index1 = shape1.Size() + index1;
    if ( index2 < 0 ) index2 = shape2.Size() + index2;
    return (index1 >= 0 && shape1.Size() > index1 && index2 >= 0 && shape2.Size() > index2 && shape1[index1] == shape2[index2]);
}

static Shape broadcastShape(const Shape &shape1, const Shape &shape2)
{
    if ( shape1.Size() != shape2.Size() ) throw std::invalid_argument("ERROR_IF(rank(shape1) != rank(shape2))");
    Shape shape = shape1;
    for ( auto i = 0; i < shape.Size(); i++ )
    {
        if ( shape[i] == 1 )
        {
            shape[i] = shape2[i];
        }
        else
        {
            if ( shape2[i] != 1 && shape2[i] != shape[i] )
                throw std::invalid_argument("ERROR_IF(shape2[i] != 1 && shape2[i] != shape[i])");
        }
    }
    return shape;
}

static Shape GetShapeFromValues(const Tensor *tensor)
{
    if ( tensor )
    {
        assert(tensor->IsConstant());
        const auto values = tensor->View().Values<int>(tensor->Type());
        return Shape(values.begin(), values.Count());
    }
    return {};
}

namespace tosa
{
namespace validator
{
namespace checks
{
// Checks for TOSA Specification 1.0.0draft
void ErrorIfCheck_3tg4p2a5te0jy(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: REDUCE_ALL, REDUCE_ANY, REDUCE_MAX, REDUCE_MIN, REDUCE_PRODUCT, REDUCE_SUM,
    static constexpr char constraint[] = "ERROR_IF(axis < 0 || axis >= rank(shape1))";
    const auto rank = op->Input(TensorUsage::IFM)->shape.Size();
    const auto &inputShape = op->Input(TensorUsage::IFM)->shape;
    auto *attr = op->Attribute<regor::axis_attr_t>();
    if ( attr->axis < 0 || attr->axis >= rank ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_gpp861oen43y(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: ARGMAX,
    static constexpr char constraint[] = "ERROR_IF(flatten(left_shape, right_shape) != shape)";
    const auto &inputShape = op->Input(TensorUsage::IFM)->shape;
    auto *attr = op->Attribute<regor::axis_attr_t>();
    const auto &expectedOutputShape = inputShape.Size() > 1 ? inputShape.Erase(attr->axis) : Shape{1};
    const auto &outputShape = op->Output(TensorUsage::OFM)->shape;
    if ( outputShape != expectedOutputShape ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_2nanft1ivm5fj(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: AVG_POOL2D,
    static constexpr char constraint[] = "ERROR_IF(!is_same<in_out_t,i8_t>() && input_zp != 0)";
    const auto in_t = op->IFM(0)->Type();
    const auto zp_tensor = op->Input(TensorUsage::Params)->tensor.get();
    const auto input_zp = zp_tensor->View().Values<int>(zp_tensor->Type())[0];
    if ( in_t != DataType::Int8 && input_zp != 0 ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_1ga3gcg4zkrkv(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: AVG_POOL2D, NEGATE,
    static constexpr char constraint[] = "ERROR_IF(!is_same<in_out_t,i8_t>() && output_zp != 0)";
    const auto out_t = op->OFM()->Type();
    const auto output_zp = Scalar<int>(*op->Input(TensorUsage::Params1)->tensor);
    if ( out_t != DataType::Int8 && output_zp != 0 ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_36r4wpx3psd81(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: AVG_POOL2D, MAX_POOL2D,
    static constexpr char constraint[] = "ERROR_IF(kernel_y < 1 || kernel_x < 1)";
    const auto *kernel = op->Kernel();
    if ( kernel->Size().y < 1 || kernel->Size().x < 1 ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_1lrylbkd3w7ix(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: AVG_POOL2D, CONV2D, DEPTHWISE_CONV2D, MAX_POOL2D, TRANSPOSE_CONV2D,
    static constexpr char constraint[] = "ERROR_IF(stride_y < 1 || stride_x < 1)";
    const auto *kernel = op->Kernel();
    if ( kernel->Stride().y < 1 || kernel->Stride().x < 1 ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_ojmgqziimenu(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: AVG_POOL2D, CONV2D, DEPTHWISE_CONV2D, MAX_POOL2D,
    static constexpr char constraint[] = "ERROR_IF(pad_top < 0 || pad_bottom < 0 || pad_left < 0 || pad_right < 0)";
    const auto *kernel = op->Kernel();
    if ( kernel->Padding().Top() < 0 || kernel->Padding().Bottom() < 0 || kernel->Padding().Left() < 0 ||
         kernel->Padding().Right() < 0 )
        throw std::invalid_argument(constraint);
}

void ErrorIfCheck_3vqy81ueu5wjk(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: AVG_POOL2D, MAX_POOL2D,
    static constexpr char constraint[] = "ERROR_IF(pad_right >= kernel_x || pad_left >= kernel_x)";
    const auto *kernel = op->Kernel();
    if ( kernel->Padding().Right() >= kernel->Size().x || kernel->Padding().Left() >= kernel->Size().x )
        throw std::invalid_argument(constraint);
}

void ErrorIfCheck_125xuezh1964i(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: AVG_POOL2D, MAX_POOL2D,
    static constexpr char constraint[] = "ERROR_IF(pad_top >= kernel_y || pad_bottom >= kernel_y)";
    const auto *kernel = op->Kernel();
    if ( kernel->Padding().Top() >= kernel->Size().y || kernel->Padding().Bottom() >= kernel->Size().y )
        throw std::invalid_argument(constraint);
}

void ErrorIfCheck_fqta626ku4qe(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: AVG_POOL2D, MAX_POOL2D,
    static constexpr char constraint[] = "ERROR_IF(OH != idiv_check(IH + pad_top + pad_bottom - kernel_y, stride_y) + 1)";
    auto IH = op->Input(TensorUsage::IFM)->shape.Height();
    auto OH = op->Output(TensorUsage::OFM)->shape.Height();
    int64_t tmp =
        static_cast<int64_t>(IH) + op->Kernel()->Padding().Top() + op->Kernel()->Padding().Bottom() -
        op->Kernel()->Size().y;
    if ( tmp % op->Kernel()->Stride().y != 0 ) throw std::invalid_argument(constraint);
    if ( OH != tmp / op->Kernel()->Stride().y + 1 ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_ycjhrvf2yigr(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: AVG_POOL2D, MAX_POOL2D,
    static constexpr char constraint[] = "ERROR_IF(OW != idiv_check(IW + pad_left + pad_right - kernel_x, stride_x) + 1)";
    auto IW = op->Input(TensorUsage::IFM)->shape.Width();
    auto OW = op->Output(TensorUsage::OFM)->shape.Width();
    int64_t tmp =
        static_cast<int64_t>(IW) + op->Kernel()->Padding().Left() + op->Kernel()->Padding().Right() -
        op->Kernel()->Size().x;
    if ( tmp % op->Kernel()->Stride().x != 0 ) throw std::invalid_argument(constraint);
    if ( OW != tmp / op->Kernel()->Stride().x + 1 ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_1c57olj698f3d(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: AVG_POOL2D, MAX_POOL2D, RESIZE,
    static constexpr char constraint[] = "ERROR_IF(shapeCheck(output, [N,OH,OW,C], input, [N,IH,IW,C]))";
    const auto *input = op->Input(TensorUsage::IFM);
    const auto *output = op->Output(TensorUsage::OFM);
    if ( !shapeCheck(input, 0, output, 0) ) throw std::invalid_argument(constraint);  // N
    if ( !shapeCheck(input, 3, output, 3) ) throw std::invalid_argument(constraint);  // C
}

void ErrorIfCheck_1hrio849y2qnx(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: CONV2D, CONV3D, DEPTHWISE_CONV2D, TRANSPOSE_CONV2D,
    static constexpr char constraint[] = "ERROR_IF(!is_same<in_t,i8_t>() && input_zp != 0)";
    const auto in_t = op->IFM(0)->Type();
    const auto input_zp = Scalar<int>(*op->Input(TensorUsage::Params)->tensor);
    if ( in_t != DataType::Int8 && input_zp != 0 ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_31vgfyg6fi9t6(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: CONV2D,
    static constexpr char constraint[] = "ERROR_IF(!is_same<weight_t,int8_t>() && weight_zp != 0)";
    const auto weight_t = op->Input(TensorUsage::Weights)->tensor->Type();
    const auto zp_param = op->Input(TensorUsage::Params1);
    const auto weight_zp = Scalar<int>(*zp_param->tensor);
    if ( weight_t != DataType::Int8 && weight_zp != 0 ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_3fzsq78v5ypau(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: CONV2D, DEPTHWISE_CONV2D,
    static constexpr char constraint[] = "ERROR_IF(dilation_y < 1 || dilation_x < 1)";
    const auto *kernel = op->Kernel();
    if ( kernel->Dilation().y < 1 || kernel->Dilation().x < 1 ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_2vhj6e48eyzlr(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: CONV2D, CONV3D, DEPTHWISE_CONV2D,
    static constexpr char constraint[] = "ERROR_IF(OH != idiv_check(IH - 1 + pad_top + pad_bottom - (KH - 1) * dilation_y, stride_y) + 1)";
    auto IH = op->Input(TensorUsage::IFM)->shape.Height();
    int WeightHeightIndex =
        (op->Type() == regor::OpType::DepthwiseConv2D) ?
            0 :
        (op->Type() == regor::OpType::Conv3D) ?
            2 :
            1;
    auto KH = op->Input(TensorUsage::Weights)->shape[WeightHeightIndex];
    auto OH = op->Output(TensorUsage::OFM)->shape.Height();
    const auto &padding = op->Kernel()->Padding();
    const auto &stride = op->Kernel()->Stride();
    const auto &dilation = op->Kernel()->Dilation();
    if ( KH < 1 || dilation.y < 0 || padding.Top() < 0 || padding.Bottom() < 0 || stride.y < 1 )
        throw std::invalid_argument(constraint);
    int64_t term1 = IH - 1LL + padding.Top() + padding.Bottom();
    int64_t term2 = (KH - 1LL) * dilation.y;
    if ( term1 < 0 || term2 < 0 || term2 > term1 ) throw std::invalid_argument(constraint);
    if ( term2 >= std::numeric_limits<int64_t>::max() - 3LL * std::numeric_limits<int>::max() - 1 )
        throw std::invalid_argument(constraint);

    int64_t numerator = term1 - term2;
    if ( numerator % stride.y != 0 ) throw std::invalid_argument(constraint);
    if ( OH != numerator / stride.y + 1 ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_147wc580l2tik(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: CONV2D, CONV3D, DEPTHWISE_CONV2D,
    static constexpr char constraint[] = "ERROR_IF(OW != idiv_check(IW - 1 + pad_left + pad_right - (KW - 1) * dilation_x, stride_x) + 1)";
    auto IW = op->Input(TensorUsage::IFM)->shape.Width();
    int WeightWitdhIndex =
        (op->Type() == regor::OpType::DepthwiseConv2D) ?
            1 :
        (op->Type() == regor::OpType::Conv3D) ?
            3 :
            2;
    auto KW = op->Input(TensorUsage::Weights)->shape[WeightWitdhIndex];
    auto OW = op->Output(TensorUsage::OFM)->shape.Width();
    const auto &padding = op->Kernel()->Padding();
    const auto &stride = op->Kernel()->Stride();
    const auto &dilation = op->Kernel()->Dilation();
    if ( KW < 1 || dilation.x < 0 || padding.Left() < 0 || padding.Right() < 0 || stride.x < 1 )
        throw std::invalid_argument(constraint);
    int64_t term1 = IW - 1LL + padding.Left() + padding.Right();
    int64_t term2 = (KW - 1LL) * dilation.x;
    if ( term1 < 0 || term2 < 0 || term2 > term1 ) throw std::invalid_argument(constraint);
    if ( term2 >= std::numeric_limits<int64_t>::max() - 3LL * std::numeric_limits<int>::max() - 1 )
        throw std::invalid_argument(constraint);
    int64_t numerator = term1 - term2;
    if ( numerator % stride.x != 0 ) throw std::invalid_argument(constraint);
    if ( OW != numerator / stride.x + 1 ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_1gr4n0iszdlxr(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: CONV2D, CONV3D, FULLY_CONNECTED, TRANSPOSE_CONV2D,
    static constexpr char constraint[] = "ERROR_IF(BC != OC && BC != 1)";
    const auto *bias = op->Input(TensorUsage::Scales);
    const auto *output = op->Output(TensorUsage::OFM);
    if ( (bias->shape.Elements() != 1) && !shapeCheck(output, -1, bias, 0) )
        throw std::invalid_argument(constraint);  // OC
}

void ErrorIfCheck_2rm8rnsdfn14h(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: CONV2D, TRANSPOSE_CONV2D,
    static constexpr char constraint[] = "ERROR_IF(shapeCheck(output, [N,OH,OW,OC], input, [N,IH,IW,IC]))";
    const auto *input = op->Input(TensorUsage::IFM);
    const auto *output = op->Output(TensorUsage::OFM);
    if ( !shapeCheck(input, 0, output, 0) ) throw std::invalid_argument(constraint);  // N
}

void ErrorIfCheck_36emtx7zwkk96(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: CONV2D, TRANSPOSE_CONV2D,
    static constexpr char constraint[] = "ERROR_IF(shapeCheck(output, [N,OH,OW,OC], weight, [OC,KH,KW,IC]))";
    const auto *weights = op->Input(TensorUsage::Weights);
    const auto *output = op->Output(TensorUsage::OFM);
    if ( !shapeCheck(output, 3, weights, 0) ) throw std::invalid_argument(constraint);  // OC
}

void ErrorIfCheck_cr43yjpqkcpd(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: CONV2D, TRANSPOSE_CONV2D,
    static constexpr char constraint[] = "ERROR_IF(shapeCheck(weight, [OC,KH,KW,IC], input, [N,IH,IW,IC]))";
    const auto *weight = op->Input(TensorUsage::Weights);
    const auto *input = op->Input(TensorUsage::IFM);
    if ( !shapeCheck(weight, 3, input, 3) ) throw std::invalid_argument(constraint);  // IC
}

void ErrorIfCheck_3m5ijs493bw6j(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: CONV3D, DEPTHWISE_CONV2D, TRANSPOSE_CONV2D,
    static constexpr char constraint[] = "ERROR_IF(!is_same<weight_t,i8_t>() && weight_zp != 0)";
    const auto weight_t = op->Input(TensorUsage::Weights)->tensor->Type();
    const auto weight_zp = Scalar<int>(*op->Input(TensorUsage::Params1)->tensor);
    if ( weight_t != DataType::Int8 && weight_zp != 0 ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_341t6ysqc16b2(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: CONV3D,
    static constexpr char constraint[] = "ERROR_IF(pad_d0 < 0 || pad_d1 < 0 || pad_top < 0 || pad_bottom < 0 || pad_left < 0 || pad_right < 0)";
    const auto &padding = op->Kernel()->Padding();
    if ( padding.Top() < 0 || padding.Bottom() < 0 || padding.Left() < 0 || padding.Right() < 0 || padding.Near() < 0 || padding.Far() < 0 )
        throw std::invalid_argument(constraint);
}

void ErrorIfCheck_uqm570jwaqb6(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: CONV3D,
    static constexpr char constraint[] = "ERROR_IF(stride_d < 1 || stride_y < 1 || stride_x < 1)";
    const auto stride = op->Kernel()->Stride3D();
    if ( stride.z < 1 || stride.y < 1 || stride.x < 1 ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_34iiwt6o66qfa(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: CONV3D,
    static constexpr char constraint[] = "ERROR_IF(dilation_d < 1 || dilation_y < 1 || dilation_x < 1)";
    const auto dilation = op->Kernel()->Dilation3D();
    if ( dilation.z < 1 || dilation.y < 1 || dilation.x < 1 ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_llbd3iugmek0(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: CONV3D,
    static constexpr char constraint[] = "ERROR_IF(OD != idiv_check(ID - 1 + pad_d0 + pad_d1 - (KD - 1) * dilation_d, stride_d) + 1)";
    auto ID = op->Input(TensorUsage::IFM)->shape[1];
    auto KD = op->Input(TensorUsage::Weights)->shape[1];
    auto OD = op->Output(TensorUsage::OFM)->shape[1];
    const auto *kernel = op->Kernel();
    const auto &padding = kernel->Padding();
    const auto &dilation = kernel->Dilation3D();
    const auto &stride = kernel->Stride3D();
    if ( KD < 1 || dilation.z < 0 || padding.Near() < 0 || padding.Far() < 0 || stride.z < 1 )
        throw std::invalid_argument(constraint);
    int64_t term1 = ID - 1LL + padding.Near() + padding.Far();
    int64_t term2 = (KD - 1LL) * dilation.z;
    if ( term1 < 0 || term2 < 0 || term2 > term1 ) throw std::invalid_argument(constraint);
    if ( term2 >= std::numeric_limits<int64_t>::max() - 3LL * std::numeric_limits<int>::max() - 1 )
        throw std::invalid_argument(constraint);
    int64_t numerator = term1 - term2;
    if ( numerator % stride.z != 0 ) throw std::invalid_argument(constraint);
    if ( OD != numerator / stride.z + 1 ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_1w510kxt5b2b2(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: CONV3D,
    static constexpr char constraint[] = "ERROR_IF(shapeCheck(output, [N,OD,OH,OW,OC], input, [N,ID,IH,IW,IC]))";
    const auto *input = op->Input(TensorUsage::IFM);
    const auto *output = op->Output(TensorUsage::OFM);
    if ( !shapeCheck(input, 0, output, 0) ) throw std::invalid_argument(constraint);  // N
}

void ErrorIfCheck_27g3t38z1of4h(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: CONV3D,
    static constexpr char constraint[] = "ERROR_IF(shapeCheck(output, [N,OD,OH,OW,OC], weight, [OC,KD,KH,KW,IC]))";
    const auto *weights = op->Input(TensorUsage::Weights);
    const auto *output = op->Output(TensorUsage::OFM);
    if ( !shapeCheck(output, 4, weights, 0) ) throw std::invalid_argument(constraint);  // OC
}

void ErrorIfCheck_2cpco8ykx99sa(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: CONV3D,
    static constexpr char constraint[] = "ERROR_IF(shapeCheck(weight, [OC,KD,KH,KW,IC], input, [N,ID,IH,IW,IC]))";
    const auto *weight = op->Input(TensorUsage::Weights);
    const auto *input = op->Input(TensorUsage::IFM);
    if ( !shapeCheck(weight, 4, input, 4) ) throw std::invalid_argument(constraint);  // IC
}

void ErrorIfCheck_2d0jmyhr9lscf(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: DEPTHWISE_CONV2D,
    static constexpr char constraint[] = "ERROR_IF(BC != C*M && BC != 1)";
    const auto *bias = op->Input(TensorUsage::Scales);
    const auto *output = op->Output(TensorUsage::OFM);
    if ( (bias->shape.Elements() != 1) && !shapeCheck(output, 3, bias, 0) )
        throw std::invalid_argument(constraint);  // OC = C*M
}

void ErrorIfCheck_10td4qt70dp3i(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: DEPTHWISE_CONV2D,
    static constexpr char constraint[] = "ERROR_IF(shapeCheck(output, [N,OH,OW,C*M], input, [N,IH,IW,C]))";
    const auto *input = op->Input(TensorUsage::IFM);
    const auto *output = op->Output(TensorUsage::OFM);
    if ( !shapeCheck(input, 0, output, 0) ) throw std::invalid_argument(constraint);  // N
}

void ErrorIfCheck_1qxtjwwlh068t(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: DEPTHWISE_CONV2D,
    static constexpr char constraint[] = "ERROR_IF(shapeCheck(weight, [KH,KW,C,M], input, [N,IH,IW,C]))";
    const auto *input = op->Input(TensorUsage::IFM);
    const auto *weight = op->Input(TensorUsage::Weights);
    if ( !shapeCheck(input, 3, weight, 2) ) throw std::invalid_argument(constraint);  // C
}

void ErrorIfCheck_1hp4djlq1mi8i(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: FFT2D, RFFT2D,
    static constexpr char constraint[] = "ERROR_IF(!power_of_two(H))";
    bool checkOk = true;
    checkOk = (op != nullptr);  // TODO: Implement check when EXT-FFT is supported
    if ( !checkOk ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_20r08ymi6c43u(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: FFT2D, RFFT2D,
    static constexpr char constraint[] = "ERROR_IF(!power_of_two(W))";
    bool checkOk = true;
    checkOk = (op != nullptr);  // TODO: Implement check when EXT-FFT is supported
    if ( !checkOk ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_1xwwkxeypcw3j(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: FFT2D,
    static constexpr char constraint[] = "ERROR_IF(shapeCheck(output_imag, [N,H,W], input_real, [N,H,W]))";
    bool checkOk = true;
    checkOk = (op != nullptr);  // TODO: Implement check when EXT-FFT is supported
    if ( !checkOk ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_vi3hzxbetjyg(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: FFT2D,
    static constexpr char constraint[] = "ERROR_IF(shapeCheck(output_imag, [N,H,W], input_imag, [N,H,W]))";
    bool checkOk = true;
    checkOk = (op != nullptr);  // TODO: Implement check when EXT-FFT is supported
    if ( !checkOk ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_1m8qk2pbuovev(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: FFT2D,
    static constexpr char constraint[] = "ERROR_IF(shapeCheck(output_imag, [N,H,W], output_real, [N,H,W]))";
    bool checkOk = true;
    checkOk = (op != nullptr);  // TODO: Implement check when EXT-FFT is supported
    if ( !checkOk ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_1iv4j2x95j8dk(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: FFT2D,
    static constexpr char constraint[] = "ERROR_IF(shapeCheck(output_real, [N,H,W], input_real, [N,H,W]))";
    bool checkOk = true;
    checkOk = (op != nullptr);  // TODO: Implement check when EXT-FFT is supported
    if ( !checkOk ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_316kdwzc9jf5x(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: FFT2D,
    static constexpr char constraint[] = "ERROR_IF(shapeCheck(output_real, [N,H,W], input_imag, [N,H,W]))";
    bool checkOk = true;
    checkOk = (op != nullptr);  // TODO: Implement check when EXT-FFT is supported
    if ( !checkOk ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_tnr115b4spgw(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: FFT2D,
    static constexpr char constraint[] = "ERROR_IF(shapeCheck(input_imag, [N,H,W], input_real, [N,H,W]))";
    bool checkOk = true;
    checkOk = (op != nullptr);  // TODO: Implement check when EXT-FFT is supported
    if ( !checkOk ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_2autvayhidla8(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: MATMUL,
    static constexpr char constraint[] = "ERROR_IF(is_same<in_t,i8_t> && (A_zp != 0 || B_zp != 0))";
    const auto in_t = op->IFM(0)->Type();
    const auto A_zp = Scalar<int>(*op->Input(TensorUsage::Params0)->tensor);
    const auto B_zp = Scalar<int>(*op->Input(TensorUsage::Params1)->tensor);
    if ( in_t != DataType::Int8 && (A_zp != 0 || B_zp != 0) ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_h1uadv5irsu6(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: MATMUL,
    static constexpr char constraint[] = "ERROR_IF(shapeCheck(output, [N,H,W], A, [N,H,C]))";
    const auto *A = op->Input(TensorUsage::IFM);
    const auto *output = op->Output(TensorUsage::OFM);
    if ( !shapeCheck(A, 0, output, 0) ) throw std::invalid_argument(constraint);  // N
    if ( !shapeCheck(A, 1, output, 1) ) throw std::invalid_argument(constraint);  // H
}

void ErrorIfCheck_1kfh97qingywb(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: MATMUL,
    static constexpr char constraint[] = "ERROR_IF(shapeCheck(output, [N,H,W], B, [N,C,W]))";
    const auto *B = op->Input(TensorUsage::IFM1);
    const auto *output = op->Output(TensorUsage::OFM);
    if ( !shapeCheck(B, 0, output, 0) ) throw std::invalid_argument(constraint);  // N
    if ( !shapeCheck(B, 2, output, 2) ) throw std::invalid_argument(constraint);  // W
}

void ErrorIfCheck_1azcq4511qzyx(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: MATMUL,
    static constexpr char constraint[] = "ERROR_IF(shapeCheck(B, [N,C,W], A, [N,H,C]))";
    const auto *A = op->Input(TensorUsage::IFM);
    const auto *B = op->Input(TensorUsage::IFM1);
    if ( !shapeCheck(B, 0, A, 0) ) throw std::invalid_argument(constraint);  // N
    if ( !shapeCheck(B, 1, A, 2) ) throw std::invalid_argument(constraint);  // C
}

void ErrorIfCheck_2befn2dfjcm62(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: RFFT2D,
    static constexpr char constraint[] = "ERROR_IF(shapeCheck(output_imag, [N,H,W/2 + 1], input_real, [N,H,W]))";
    bool checkOk = true;
    checkOk = (op != nullptr);  // TODO: Implement check when EXT-FFT is supported
    if ( !checkOk ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_13tqdu59nyxyh(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: RFFT2D,
    static constexpr char constraint[] = "ERROR_IF(shapeCheck(output_imag, [N,H,W/2 + 1], output_real, [N,H,W/2 + 1]))";
    bool checkOk = true;
    checkOk = (op != nullptr);  // TODO: Implement check when EXT-FFT is supported
    if ( !checkOk ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_khc2s3en2uxi(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: RFFT2D,
    static constexpr char constraint[] = "ERROR_IF(shapeCheck(output_real, [N,H,W/2 + 1], input_real, [N,H,W]))";
    bool checkOk = true;
    checkOk = (op != nullptr);  // TODO: Implement check when EXT-FFT is supported
    if ( !checkOk ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_q9dl3x81rc4o(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: TRANSPOSE_CONV2D,
    static constexpr char constraint[] = "ERROR_IF(out_pad_top <= -KH || out_pad_bottom <= -KH)";
    int64_t KH = op->Input(TensorUsage::Weights)->shape.Height();
    const auto *k = op->Kernel();
    if ( k->Padding().Top() <= -KH || k->Padding().Bottom() <= -KH ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_2rfkujt9lg7eq(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: TRANSPOSE_CONV2D,
    static constexpr char constraint[] = "ERROR_IF(out_pad_left <= -KW || out_pad_right <= -KW)";
    int64_t KW = op->Input(TensorUsage::Weights)->shape.Width();
    const auto *k = op->Kernel();
    if ( k->Padding().Left() <= -KW || k->Padding().Right() <= -KW ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_3nelbnmxyemot(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: TRANSPOSE_CONV2D,
    auto *attr = op->Attribute<regor::transpose_conv2d_attr_t>();
    static constexpr char constraint[] = "ERROR_IF(OH != (IH - 1) * stride_y + out_pad_top + out_pad_bottom + KH)";
    auto IH = op->Input(TensorUsage::IFM)->shape.Height();
    auto KH = op->Input(TensorUsage::Weights)->shape.Height();
    auto OH = op->Output(TensorUsage::OFM)->shape.Height();
    auto *k = op->Kernel();
    const auto &outPadTBLR = attr->outPadTBLR;
    const auto &stride = k->Stride();
    if ( IH < 1 || stride.y < 1 ) throw std::invalid_argument(constraint);
    int64_t term1 = (IH - 1LL) * stride.y;
    if ( term1 >= std::numeric_limits<int64_t>::max() - 3LL * std::numeric_limits<int>::max() )
        throw std::invalid_argument(constraint);
    int64_t term2 = static_cast<int64_t>(outPadTBLR[0]) + outPadTBLR[1] + KH;
    if ( term1 < 0 || term2 < -term1 ) throw std::invalid_argument(constraint);
    uint64_t resultH = static_cast<uint64_t>(term1) + term2;
    if ( OH != static_cast<int64_t>(resultH) ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_24conlof4w8eh(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: TRANSPOSE_CONV2D,
    auto *attr = op->Attribute<regor::transpose_conv2d_attr_t>();
    static constexpr char constraint[] = "ERROR_IF(OW != (IW - 1) * stride_x + out_pad_left + out_pad_right + KW)";
    auto IW = op->Input(TensorUsage::IFM)->shape.Width();
    auto KW = op->Input(TensorUsage::Weights)->shape.Width();
    auto OW = op->Output(TensorUsage::OFM)->shape.Width();
    auto *k = op->Kernel();
    const auto &outPadTBLR = attr->outPadTBLR;
    const auto &stride = k->Stride();
    if ( IW < 1 || stride.x < 1 ) throw std::invalid_argument(constraint);
    int64_t term1 = (IW - 1LL) * stride.x;
    if ( term1 >= std::numeric_limits<int64_t>::max() - 3LL * std::numeric_limits<int>::max() )
        throw std::invalid_argument(constraint);
    int64_t term2 = static_cast<int64_t>(outPadTBLR[2]) + outPadTBLR[3] + KW;
    if ( term1 < 0 || term2 < -term1 ) throw std::invalid_argument(constraint);
    uint64_t resultW = static_cast<uint64_t>(term1) + term2;
    if ( OW != static_cast<int64_t>(resultW) ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_xod9coigx1x2(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: CLAMP,
    static constexpr char constraint[] = "ERROR_IF(max_val < min_val)";
    auto *attr = op->Attribute<regor::clamp_attr_t>();
    if ( attr->max < attr->min ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_15y4an3ceern5(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: CLAMP,
    static constexpr char constraint[] = "ERROR_IF(isNaN(min_val) || isNaN(max_val))";
    bool checkOk = (context.profile != GraphApi::PROFILE_BASELINE);
    checkOk = (op != nullptr);  // TODO: Implement check when PRO-FP is supported
    if ( !checkOk ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_10u6py7exa66n(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: CLAMP, ERF, SIGMOID, TANH, CAST, RESCALE,
    static constexpr char constraint[] = "ERROR_IF(rankCheck(output, input))";
    const auto &outputShape = op->Output(TensorUsage::OFM)->shape;
    const auto &inputShape = op->Input(TensorUsage::IFM)->shape;
    if ( outputShape != inputShape ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_1hynqeiugz9lt(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: ADD, ARITHMETIC_RIGHT_SHIFT, BITWISE_AND, BITWISE_OR, BITWISE_XOR, INTDIV, LOGICAL_AND,
    //  LOGICAL_LEFT_SHIFT, LOGICAL_RIGHT_SHIFT, LOGICAL_OR, LOGICAL_XOR, MAXIMUM, MINIMUM, MUL, POW, SUB, EQUAL,
    //  GREATER, GREATER_EQUAL,
    static constexpr char constraint[] = "ERROR_IF(shape != broadcast_shape(shape1, shape2))";
    auto shape1 = op->Input(TensorUsage::IFM)->shape;
    auto shape2 = op->Input(TensorUsage::IFM1)->shape;
    auto shape = op->Output(TensorUsage::OFM)->shape;
    if ( shape != broadcastShape(shape1, shape2) ) throw std::invalid_argument(constraint);
}

static bool broadcastOk(const Shape &outShape, const Shape &inShape)
{
    auto inRank = inShape.Size();
    auto outRank = outShape.Size();
    if ( outRank != inRank ) return false;
    for ( int i = 0; i < outRank; i++ )
    {
        if ( outShape[i] != inShape[i] && inShape[i] != 1 ) return false;
    }
    return true;
}

void ErrorIfCheck_1yism57if6v2z(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: ADD, ARITHMETIC_RIGHT_SHIFT, BITWISE_AND, BITWISE_OR, BITWISE_XOR, INTDIV, LOGICAL_AND,
    //  LOGICAL_LEFT_SHIFT, LOGICAL_RIGHT_SHIFT, LOGICAL_OR, LOGICAL_XOR, MAXIMUM, MINIMUM, MUL, POW, SUB, SELECT,
    //  EQUAL, GREATER, GREATER_EQUAL,
    static constexpr char constraint[] = "ERROR_IF(apply_broadcast(shape, shape1, index))";
    const auto &shape = op->Output(TensorUsage::OFM)->shape;
    const auto &shape1 = op->Input(TensorUsage::IFM)->shape;

    if ( !broadcastOk(shape, shape1) ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_3k5ug2w7gxc7r(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: ADD, ARITHMETIC_RIGHT_SHIFT, BITWISE_AND, BITWISE_OR, BITWISE_XOR, INTDIV, LOGICAL_AND,
    //  LOGICAL_LEFT_SHIFT, LOGICAL_RIGHT_SHIFT, LOGICAL_OR, LOGICAL_XOR, MAXIMUM, MINIMUM, MUL, POW, SUB, SELECT,
    //  EQUAL, GREATER, GREATER_EQUAL,
    static constexpr char constraint[] = "ERROR_IF(apply_broadcast(shape, shape2, index))";
    const auto &shape = op->Output(TensorUsage::OFM)->shape;
    const auto &shape2 = op->Input(TensorUsage::IFM1)->shape;

    if ( !broadcastOk(shape, shape2) ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_396rg8p65j58r(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: TABLE, ABS, BITWISE_NOT, CEIL, CLZ, COS, EXP, FLOOR, LOG, LOGICAL_NOT, NEGATE, RECIPROCAL, RSQRT, SIN,
    //  REVERSE, IDENTITY,
    static constexpr char constraint[] = "ERROR_IF(rankCheck(output, input1))";
    const auto &outputShape = op->Output(TensorUsage::OFM)->shape;
    const auto &inputShape = op->Input(TensorUsage::IFM)->shape;
    if ( outputShape != inputShape ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_3l2ksvk26m07h(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: NEGATE,
    static constexpr char constraint[] = "ERROR_IF(!is_same<in_out_t,i8_t>() && input1_zp != 0)";
    const auto in_t = op->IFM(0)->Type();
    const auto input1_zp = Scalar<int>(*op->Input(TensorUsage::Params)->tensor);
    if ( in_t != DataType::Int8 && input1_zp != 0 ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_192e2vu3t5aqm(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: SELECT,
    static constexpr char constraint[] = "ERROR_IF(shape != broadcast_shape(broadcast_shape(shape1, shape2), shape3))";
    auto shape1 = op->Input(TensorUsage::IFM)->shape;
    auto shape2 = op->Input(TensorUsage::IFM1)->shape;
    auto shape3 = op->Input(TensorUsage::IFM2)->shape;
    auto shape = op->Output(TensorUsage::OFM)->shape;
    if ( shape != broadcastShape(broadcastShape(shape1, shape2), shape3) ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_3tccsjner0km9(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: SELECT,
    static constexpr char constraint[] = "ERROR_IF(apply_broadcast(shape, shape3, index))";
    const auto &shape = op->Output(TensorUsage::OFM)->shape;
    const auto &shape3 = op->Input(TensorUsage::IFM2)->shape;

    if ( !broadcastOk(shape, shape3) ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_33exz9gn2i1wy(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: REDUCE_ALL, REDUCE_ANY, REDUCE_MAX, REDUCE_MIN, REDUCE_PRODUCT, REDUCE_SUM,
    static constexpr char constraint[] = "ERROR_IF(shape[axis] != 1)";
    const auto &shape = op->Output(TensorUsage::OFM)->shape;
    auto *attr = op->Attribute<regor::axis_attr_t>();
    if ( shape[attr->axis] != 1 ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_2d3qdl1f70i6y(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: CONCAT,
    static constexpr char constraint[] = "ERROR_IF(input1 == [])";
    if ( op->CountInputs(TensorUsage::IFM) == 0 ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_5y7ov1oeymoa(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: CONCAT,
    static constexpr char constraint[] = "ERROR_IF(axis < 0 || axis >= max(1,rank(shapes1[0])))";
    const auto rank = op->Input(TensorUsage::IFM)->shape.Size();
    auto *attr = op->Attribute<regor::axis_attr_t>();
    if ( attr->axis < 0 || attr->axis >= std::max<int>(1, rank) ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_1aloht2b77zby(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: CONCAT,
    static constexpr char constraint[] = "ERROR_IF(rank(shapes1[shape_index]) != rank(shapes1[0]))";
    const auto ifm0Rank = op->IFM(0)->StorageShape().Size();
    const int count = op->CountInputs(TensorUsage::IFM);
    for ( int i = 1; i < count; i++ )
    {
        if ( op->IFM(i)->StorageShape().Size() != ifm0Rank ) throw std::invalid_argument(constraint);
    }
}

void ErrorIfCheck_f1kt9a6h7s2p(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: CONCAT,
    static constexpr char constraint[] = "ERROR_IF(shapes1[shape_index][axis_index] != shapes1[0][axis_index])";
    const auto attr = op->Attribute<regor::axis_attr_t>();
    const auto ifm0Shape = op->IFM(0)->StorageShape();
    const int count = op->CountInputs(TensorUsage::IFM);
    for ( int i = 1; i < count; i++ )
    {
        auto shape = op->IFM(i)->StorageShape();
        for ( int axis = 0; axis < ifm0Shape.Size(); axis++ )
        {
            if ( axis == attr->axis ) continue;
            if ( shape[axis] != ifm0Shape[axis] ) throw std::invalid_argument(constraint);
        }
    }
}

void ErrorIfCheck_302z1f8mq8lg7(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: CONCAT,
    static constexpr char constraint[] = "ERROR_IF(axis_sum != shape[axis])";
    const auto axis = op->Attribute<regor::axis_attr_t>()->axis;
    const int count = op->CountInputs(TensorUsage::IFM);
    int axis_sum = 0;
    for ( int i = 0; i < count; i++ )
    {
        axis_sum += op->IFM(i)->StorageShape()[axis];
    }
    if ( axis_sum != op->OFM()->StorageShape()[axis] ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_14z7y0qe9lwps(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: PAD,
    static constexpr char constraint[] = "ERROR_IF(rank(shape) != rank(shape1))";
    auto rank = op->Output(TensorUsage::OFM)->shape.Size();
    auto rank1 = op->Input(TensorUsage::IFM)->shape.Size();
    if ( rank != rank1 ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_3dvn5k3273lwz(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: PAD,
    static constexpr char constraint[] = "ERROR_IF(padding[i * 2] < 0 || padding[(i * 2) + 1] < 0)";
    const int rank_shape = op->OFM()->StorageShape().Size();
    const auto padding = GetShapeFromValues(op->Input(TensorUsage::Params)->tensor.get());
    for ( int i = 0; i < rank_shape; i++ )
    {
        if ( padding[i * 2] < 0 || padding[(i * 2) + 1] < 0 ) throw std::invalid_argument(constraint);
    }
}

void ErrorIfCheck_34zvbtwx1r18j(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: PAD,
    static constexpr char constraint[] = "ERROR_IF(shape[i] != padding[i * 2] + shape1[i] + padding[(i * 2) + 1])";
    const auto shape = op->OFM()->StorageShape();
    const auto shape1 = op->IFM(0)->StorageShape();
    const auto padding = GetShapeFromValues(op->Input(TensorUsage::Params)->tensor.get());
    for ( int i = 0; i < shape.Size(); i++ )
    {
        if ( shape[i] != padding[i * 2] + shape1[i] + padding[(i * 2) + 1] ) throw std::invalid_argument(constraint);
    }
}

void ErrorIfCheck_2a1jpygblc07i(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: RESHAPE, TRANSPOSE,
    static constexpr char constraint[] = "ERROR_IF(tensor_size(shape1) != tensor_size(shape))";
    const auto &shape1 = op->Input(TensorUsage::IFM)->shape;
    const auto &shape = op->Output(TensorUsage::OFM)->shape;
    if ( shape1.Elements() != shape.Elements() ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_3hthyoock2ew5(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: REVERSE,
    static constexpr char constraint[] = "ERROR_IF(axis < 0 || axis >= rank(shape))";
    const auto rank = op->Input(TensorUsage::IFM)->shape.Size();
    auto *attr = op->Attribute<regor::axis_attr_t>();
    if ( attr->axis < 0 || attr->axis >= rank ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_1nifeiq9rvmb8(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: SLICE,
    static constexpr char constraint[] = "ERROR_IF(rank(shape1) != length(start) || rank(shape1) != length(size))";
    const auto rank = op->Input(TensorUsage::IFM)->shape.Size();
    auto *attr = op->HasAttribute<regor::slice_attr_t>() ? op->Attribute<regor::slice_attr_t>() : nullptr;
    auto startConn = op->Input(TensorUsage::Params0);
    auto sizeConn = op->Input(TensorUsage::Params1);
    // Compile time constant tensor attributes takes precedence over operator attributes
    int startLength = startConn ? startConn->shape.Elements() : (attr ? attr->begin.Size() : -1);
    int sizeLength = sizeConn ? sizeConn->shape.Elements() : (attr ? attr->size.Size() : -1);
    if ( rank != startLength || rank != sizeLength ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_21rq6kn6p1yle(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: SLICE, TILE, TRANSPOSE,
    static constexpr char constraint[] = "ERROR_IF(rank(shape1) != rank(shape))";
    const auto &shape1 = op->Input(TensorUsage::IFM)->shape;
    const auto &shape = op->Output(TensorUsage::OFM)->shape;
    if ( shape1.Size() != shape.Size() ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_3rghkieqip43o(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: SLICE,
    static constexpr char constraint[] = "ERROR_IF(start[index] < 0)";
    bool checkOk = true;
    const auto rank = op->Input(TensorUsage::IFM)->shape.Size();
    auto *attr = op->HasAttribute<regor::slice_attr_t>() ? op->Attribute<regor::slice_attr_t>() : nullptr;
    auto startConn = op->Input(TensorUsage::Params0);
    // Compile time constant tensor attributes takes precedence over operator attributes
    Shape begin = startConn ? GetShapeFromValues(startConn->tensor.get()) : (attr ? attr->begin : Shape{});
    for ( int i = 0; i < rank; i++ )
    {
        if ( begin[i] < 0 )
        {
            checkOk = false;
            break;
        }
    }
    if ( !checkOk ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_1cyv9n59wyyyc(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: SLICE,
    static constexpr char constraint[] = "ERROR_IF(size[index] <= 0)";
    bool checkOk = true;
    const auto rank = op->Input(TensorUsage::IFM)->shape.Size();
    auto *attr = op->HasAttribute<regor::slice_attr_t>() ? op->Attribute<regor::slice_attr_t>() : nullptr;
    auto sizeConn = op->Input(TensorUsage::Params1);
    // Compile time constant tensor attributes takes precedence over operator attributes
    Shape size = sizeConn ? GetShapeFromValues(sizeConn->tensor.get()) : (attr ? attr->size : Shape{});
    for ( int i = 0; i < rank; i++ )
    {
        if ( size[i] < 0 )
        {
            checkOk = false;
            break;
        }
    }
    if ( !checkOk ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_3oy2tclc6uhsu(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: SLICE,
    static constexpr char constraint[] = "ERROR_IF(start[index] + size[index] > shape1[index])";
    bool checkOk = true;
    const auto &shape = op->Input(TensorUsage::IFM)->shape;
    const auto rank = shape.Size();
    auto *attr = op->HasAttribute<regor::slice_attr_t>() ? op->Attribute<regor::slice_attr_t>() : nullptr;
    auto startConn = op->Input(TensorUsage::Params0);
    auto sizeConn = op->Input(TensorUsage::Params1);
    // Compile time constant tensor attributes takes precedence over operator attributes
    Shape begin = startConn ? GetShapeFromValues(startConn->tensor.get()) : (attr ? attr->begin : Shape{});
    Shape size = sizeConn ? GetShapeFromValues(sizeConn->tensor.get()) : (attr ? attr->size : Shape{});
    for ( int i = 0; i < rank; i++ )
    {
        int64_t sliceSize = begin[i] + size[i];
        if ( sliceSize > shape[i] )
        {
            checkOk = false;
            break;
        }
    }
    if ( !checkOk ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_gpp3enlp1ddg(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: SLICE,
    static constexpr char constraint[] = "ERROR_IF(shape[index] != size[index])";
    const auto &shape = op->Output(TensorUsage::OFM)->shape;
    const auto rank = shape.Size();
    auto *attr = op->HasAttribute<regor::slice_attr_t>() ? op->Attribute<regor::slice_attr_t>() : nullptr;
    auto sizeConn = op->Input(TensorUsage::Params1);
    // Compile time constant tensor attributes takes precedence over operator attributes
    Shape size = sizeConn ? GetShapeFromValues(sizeConn->tensor.get()) : (attr ? attr->size : Shape{});
    for ( int i = 0; i < rank; i++ )
    {
        if ( shape[i] != size[i] ) throw std::invalid_argument(constraint);
    }
}

void ErrorIfCheck_ix9div4ld46q(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: SLICE,
    static constexpr char constraint[] = "ERROR_IF(shapeCheck(size, [rank(shape1)], start, [rank(shape1)]))";
    auto rank = op->Input(TensorUsage::IFM)->shape.Size();
    auto *attr = op->HasAttribute<regor::slice_attr_t>() ? op->Attribute<regor::slice_attr_t>() : nullptr;
    auto startConn = op->Input(TensorUsage::Params0);
    auto sizeConn = op->Input(TensorUsage::Params1);
    // Compile time constant tensor attributes takes precedence over operator attributes
    int startLength = startConn ? startConn->shape.Elements() : (attr ? attr->begin.Size() : -1);
    int sizeLength = sizeConn ? sizeConn->shape.Elements() : (attr ? attr->size.Size() : -1);
    if ( startLength != rank || sizeLength != rank ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_3estuseky2gm2(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: TILE,
    static constexpr char constraint[] = "ERROR_IF(shape1[i] * multiples[i] != shape[i])";
    const auto &shape = op->Output(TensorUsage::OFM)->shape;
    const auto &shape1 = op->Input(TensorUsage::IFM)->shape;
    Shape multiples = GetShapeFromValues(op->Input(TensorUsage::Params)->tensor.get());

    if ( multiples.Size() != shape.Size() ) throw std::invalid_argument(constraint);
    for ( int i = 0; i < shape.Size(); i++ )
    {
        int64_t shape1Dim = shape1[i];
        if ( shape1Dim < 0 || multiples[i] < 0 || shape[i] < 0 ) throw std::invalid_argument(constraint);
        int64_t result = shape1Dim * multiples[i];
        if ( result > std::numeric_limits<int>::max() ) throw std::invalid_argument(constraint);
        if ( int(result) != shape[i] ) throw std::invalid_argument(constraint);
    }
}

void ErrorIfCheck_5bq1fx1llv8(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: TRANSPOSE,
    static constexpr char constraint[] = "ERROR_IF(index >= rank(shape1))";
    auto rank = op->Input(TensorUsage::IFM)->shape.Size();
    const auto &perm = op->Attribute<regor::transpose_attr_t>()->perm;
    for ( int i = 0; i < perm.Size(); i++ )
    {
        if ( perm[i] >= rank ) throw std::invalid_argument(constraint);
    }
}

void ErrorIfCheck_ckwpttzajw06(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: TRANSPOSE,
    static constexpr char constraint[] = "ERROR_IF(index < 0)";
    const auto &perm = op->Attribute<regor::transpose_attr_t>()->perm;
    for ( int i = 0; i < perm.Size(); i++ )
    {
        if ( perm[i] < 0 ) throw std::invalid_argument(constraint);
    }
}

void ErrorIfCheck_2n1ratxgd89tx(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: TRANSPOSE,
    static constexpr char constraint[] = "ERROR_IF(indexes_used[index] == true)";
    auto rank = op->Input(TensorUsage::IFM)->shape.Size();
    const auto &perm = op->Attribute<regor::transpose_attr_t>()->perm;
    Shape indexes_used(nullptr, rank);
    for ( int i = 0; i < perm.Size(); i++ )
    {
        if ( (perm[i] < 0 || perm[i] >= indexes_used.Size()) || indexes_used[perm[i]] )
            throw std::invalid_argument(constraint);
        indexes_used[perm[i]] = 1;
    }
}

void ErrorIfCheck_aizwrn95lb0l(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: TRANSPOSE,
    static constexpr char constraint[] = "ERROR_IF(shape1[perms[i]] != shape[i])";
    const auto &shape = op->Output(TensorUsage::OFM)->shape;
    const auto &shape1 = op->Input(TensorUsage::IFM)->shape;
    const auto &perm = op->Attribute<regor::transpose_attr_t>()->perm;
    for ( int i = 0; i < perm.Size(); i++ )
    {
        if ( perm[i] < 0 || perm[i] >= shape.Size() ) throw std::invalid_argument(constraint);
        if ( shape1[perm[i]] != shape[i] ) throw std::invalid_argument(constraint);
    }
}

void ErrorIfCheck_294afuxnedk9i(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: GATHER,
    static constexpr char constraint[] = "ERROR_IF(shapeCheck(output, [N,W,C], values, [N,K,C]))";
    const auto *values = op->Input(TensorUsage::IFM);
    const auto *output = op->Output(TensorUsage::OFM);
    if ( !shapeCheck(output, 0, values, 0) ) throw std::invalid_argument(constraint);  // N
    if ( !shapeCheck(output, 2, values, 2) ) throw std::invalid_argument(constraint);  // C
}

void ErrorIfCheck_27p0n0pjt2bd6(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: GATHER,
    static constexpr char constraint[] = "ERROR_IF(shapeCheck(output, [N,W,C], indices, [N,W]))";
    const auto *indices = op->Input(TensorUsage::IFM1);
    const auto *output = op->Output(TensorUsage::OFM);
    if ( !shapeCheck(output, 0, indices, 0) ) throw std::invalid_argument(constraint);  // N
    if ( !shapeCheck(output, 1, indices, 1) ) throw std::invalid_argument(constraint);  // W
}

void ErrorIfCheck_1uwmsen32dse1(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: GATHER,
    static constexpr char constraint[] = "ERROR_IF(shapeCheck(indices, [N,W], values, [N,K,C]))";
    const auto *values = op->Input(TensorUsage::IFM);
    const auto *indices = op->Input(TensorUsage::IFM1);
    if ( !shapeCheck(indices, 0, values, 0) ) throw std::invalid_argument(constraint);  // N
}

void ErrorIfCheck_3c5bq3iswjd1x(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: SCATTER,
    static constexpr char constraint[] = "ERROR_IF(shapeCheck(values_out, [N,K,C], values_in, [N,K,C]))";
    const auto *values_in = op->Input(TensorUsage::IFM);
    const auto *values_out = op->Output(TensorUsage::OFM);
    if ( !shapeCheck(values_out, 0, values_in, 0) ) throw std::invalid_argument(constraint);  // N
    if ( !shapeCheck(values_out, 1, values_in, 1) ) throw std::invalid_argument(constraint);  // K
    if ( !shapeCheck(values_out, 2, values_in, 2) ) throw std::invalid_argument(constraint);  // C
}

void ErrorIfCheck_53yuoon46swi(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: SCATTER,
    static constexpr char constraint[] = "ERROR_IF(shapeCheck(values_out, [N,K,C], indices, [N,W]))";
    const auto *indices = op->Input(TensorUsage::IFM1);
    const auto *values_out = op->Output(TensorUsage::OFM);
    if ( !shapeCheck(values_out, 0, indices, 0) ) throw std::invalid_argument(constraint);  // N
}

void ErrorIfCheck_q9pgbwuvutqu(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: SCATTER,
    static constexpr char constraint[] = "ERROR_IF(shapeCheck(values_out, [N,K,C], input, [N,W,C]))";
    const auto *input = op->Input(TensorUsage::IFM2);
    const auto *values_out = op->Output(TensorUsage::OFM);
    if ( !shapeCheck(values_out, 0, input, 0) ) throw std::invalid_argument(constraint);  // N
    if ( !shapeCheck(values_out, 2, input, 2) ) throw std::invalid_argument(constraint);  // C
}

void ErrorIfCheck_1qdcccs22lqtr(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: SCATTER,
    static constexpr char constraint[] = "ERROR_IF(shapeCheck(input, [N,W,C], values_in, [N,K,C]))";
    const auto *input = op->Input(TensorUsage::IFM2);
    const auto *values_in = op->Input(TensorUsage::IFM);
    if ( !shapeCheck(input, 0, values_in, 0) ) throw std::invalid_argument(constraint);  // N
    if ( !shapeCheck(input, 2, values_in, 2) ) throw std::invalid_argument(constraint);  // C
}

void ErrorIfCheck_2azl8wc8mbsrj(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: SCATTER,
    static constexpr char constraint[] = "ERROR_IF(shapeCheck(input, [N,W,C], indices, [N,W]))";
    const auto *input = op->Input(TensorUsage::IFM2);
    const auto *indices = op->Input(TensorUsage::IFM1);
    if ( !shapeCheck(input, 0, indices, 0) ) throw std::invalid_argument(constraint);  // N
    if ( !shapeCheck(input, 1, indices, 1) ) throw std::invalid_argument(constraint);  // W
}

void ErrorIfCheck_122a36k26p0au(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: SCATTER,
    static constexpr char constraint[] = "ERROR_IF(shapeCheck(indices, [N,W], values_in, [N,K,C]))";
    const auto *values_in = op->Input(TensorUsage::IFM);
    const auto *indices = op->Input(TensorUsage::IFM1);
    if ( !shapeCheck(indices, 0, values_in, 0) ) throw std::invalid_argument(constraint);  // N
}

void ErrorIfCheck_3sfcy967j2w8w(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: RESIZE,
    static constexpr char constraint[] = "ERROR_IF(max(OH,OW,IH,IW) >= 16384)";
    auto IW = op->Input(TensorUsage::IFM)->shape.Width();
    auto IH = op->Input(TensorUsage::IFM)->shape.Height();
    auto OW = op->Output(TensorUsage::OFM)->shape.Width();
    auto OH = op->Output(TensorUsage::OFM)->shape.Height();
    if ( std::max({OH, OW, IH, IW}) >= 16384 ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_1obslcewwn583(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: RESIZE,
    static constexpr char constraint[] = "ERROR_IF(scale_y_n <= 0 || scale_y_d <= 0 || scale_x_n <= 0 || scale_x_d <= 0)";
    const auto *attr = op->Attribute<regor::resize_attr_t>();
    const auto scaleConn = op->Input(TensorUsage::Params);
    Shape scale = scaleConn ? GetShapeFromValues(scaleConn->tensor.get()) : Shape{};
    // Compile time constant tensor attributes takes precedence over operator attributes
    auto scale_y_d = scale ? scale[1] : attr->scaleY.d;
    auto scale_y_n = scale ? scale[0] : attr->scaleY.n;
    auto scale_x_d = scale ? scale[3] : attr->scaleX.d;
    auto scale_x_n = scale ? scale[2] : attr->scaleX.n;
    if ( scale_y_n <= 0 || scale_y_d <= 0 || scale_x_n <= 0 || scale_x_d <= 0 ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_3oxfjen91qb6l(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: RESIZE,
    static constexpr char constraint[] = "ERROR_IF(scale_y_n > (1 << 11) || scale_x_n > (1 << 11))";
    const auto *attr = op->Attribute<regor::resize_attr_t>();
    const auto scaleConn = op->Input(TensorUsage::Params);
    Shape scale = scaleConn ? GetShapeFromValues(scaleConn->tensor.get()) : Shape{};
    // Compile time constant tensor attributes takes precedence over operator attributes
    auto scale_y_n = scale ? scale[0] : attr->scaleY.n;
    auto scale_x_n = scale ? scale[2] : attr->scaleX.n;
    if ( scale_y_n > (1 << 11) || scale_x_n > (1 << 11) ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_1uo0z247e42af(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: RESIZE,
    static constexpr char constraint[] = "ERROR_IF(scale_y_d >= 16 * scale_y_n || scale_x_d >= 16 * scale_x_n)";
    const auto *attr = op->Attribute<regor::resize_attr_t>();
    const auto scaleConn = op->Input(TensorUsage::Params);
    Shape scale = scaleConn ? GetShapeFromValues(scaleConn->tensor.get()) : Shape{};
    // Compile time constant tensor attributes takes precedence over operator attributes
    auto scale_y_d = scale ? scale[1] : attr->scaleY.d;
    auto scale_y_n = scale ? scale[0] : attr->scaleY.n;
    auto scale_x_d = scale ? scale[3] : attr->scaleX.d;
    auto scale_x_n = scale ? scale[2] : attr->scaleX.n;
    if ( scale_y_d >= 16 * scale_y_n || scale_x_d >= 16 * scale_x_n ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_1eovh9pyc6tyw(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: RESIZE,
    static constexpr char constraint[] = "ERROR_IF(offset_y < -scale_y_n || offset_y >= 16 * scale_y_n)";
    const auto *attr = op->Attribute<regor::resize_attr_t>();
    const auto scaleConn = op->Input(TensorUsage::Params0);
    const auto offsetConn = op->Input(TensorUsage::Params1);
    Shape scale = scaleConn ? GetShapeFromValues(scaleConn->tensor.get()) : Shape{};
    Shape offset = offsetConn ? GetShapeFromValues(offsetConn->tensor.get()) : Shape{};
    // Compile time constant tensor attributes takes precedence over operator attributes
    auto offset_y = offset ? offset[0] : attr->offset.y;
    auto scale_y_n = scale ? scale[0] : attr->scaleY.n;
    if ( offset_y < -scale_y_n || offset_y >= 16 * scale_y_n ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_24jsin2zkf4ug(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: RESIZE,
    static constexpr char constraint[] = "ERROR_IF(offset_x < -scale_x_n || offset_x >= 16 * scale_x_n)";
    const auto *attr = op->Attribute<regor::resize_attr_t>();
    const auto scaleConn = op->Input(TensorUsage::Params0);
    const auto offsetConn = op->Input(TensorUsage::Params1);
    Shape scale = scaleConn ? GetShapeFromValues(scaleConn->tensor.get()) : Shape{};
    Shape offset = offsetConn ? GetShapeFromValues(offsetConn->tensor.get()) : Shape{};
    // Compile time constant tensor attributes takes precedence over operator attributes
    auto offset_x = offset ? offset[1] : attr->offset.x;
    auto scale_x_n = scale ? scale[2] : attr->scaleX.n;
    if ( offset_x < -scale_x_n || offset_x >= 16 * scale_x_n ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_12uj5fltk5rbo(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: RESIZE,
    static constexpr char constraint[] = "ERROR_IF(border_y < -16 * scale_y_n || border_y >= scale_y_n)";
    const auto *attr = op->Attribute<regor::resize_attr_t>();
    const auto scaleConn = op->Input(TensorUsage::Params0);
    const auto borderConn = op->Input(TensorUsage::Params2);
    Shape scale = scaleConn ? GetShapeFromValues(scaleConn->tensor.get()) : Shape{};
    Shape border = borderConn ? GetShapeFromValues(borderConn->tensor.get()) : Shape{};
    // Compile time constant tensor attributes takes precedence over operator attributes
    auto border_y = border ? border[0] : attr->border.y;
    auto scale_y_n = scale ? scale[0] : attr->scaleY.n;
    if ( border_y < -16 * scale_y_n || border_y >= scale_y_n ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_1py9f91imwjxe(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: RESIZE,
    static constexpr char constraint[] = "ERROR_IF(border_x < -16 * scale_x_n || border_x >= scale_x_n)";
    const auto *attr = op->Attribute<regor::resize_attr_t>();
    const auto scaleConn = op->Input(TensorUsage::Params0);
    const auto borderConn = op->Input(TensorUsage::Params2);
    Shape scale = scaleConn ? GetShapeFromValues(scaleConn->tensor.get()) : Shape{};
    Shape border = borderConn ? GetShapeFromValues(borderConn->tensor.get()) : Shape{};
    // Compile time constant tensor attributes takes precedence over operator attributes
    auto border_x = border ? border[1] : attr->border.x;
    auto scale_x_n = scale ? scale[2] : attr->scaleY.n;
    if ( border_x < -16 * scale_x_n || border_x >= scale_x_n ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_fn614zzdrdfd(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: RESIZE,
    static constexpr char constraint[] = "ERROR_IF(OH != idiv_check((IH - 1) * scale_y_n - offset_y + border_y, scale_y_d) + 1)";
    auto IH = op->Input(TensorUsage::IFM)->shape.Height();
    auto OH = op->Output(TensorUsage::OFM)->shape.Height();
    const auto *attr = op->Attribute<regor::resize_attr_t>();
    const auto scaleConn = op->Input(TensorUsage::Params0);
    const auto offsetConn = op->Input(TensorUsage::Params1);
    const auto borderConn = op->Input(TensorUsage::Params2);
    Shape scale = scaleConn ? GetShapeFromValues(scaleConn->tensor.get()) : Shape{};
    Shape offset = offsetConn ? GetShapeFromValues(offsetConn->tensor.get()) : Shape{};
    Shape border = borderConn ? GetShapeFromValues(borderConn->tensor.get()) : Shape{};
    // Compile time constant tensor attributes takes precedence over operator attributes
    auto scale_y_n = scale ? scale[0] : attr->scaleY.n;
    auto scale_y_d = scale ? scale[1] : attr->scaleY.d;
    if ( scale_y_n > (1 << 11) || scale_y_d >= 16 * scale_y_n ) throw std::invalid_argument(constraint);
    auto offset_y = offset ? offset[0] : attr->offset.y;
    if ( offset_y < -scale_y_n || offset_y >= 16 * scale_y_n ) throw std::invalid_argument(constraint);
    if ( IH < 1 || IH >= std::numeric_limits<int16_t>::max() || scale_y_n <= 0 || scale_y_d <= 0 )
        throw std::invalid_argument(constraint);
    int64_t term1 = (IH - 1LL) * scale_y_n;
    if ( term1 >= std::numeric_limits<int64_t>::max() - 2LL * std::numeric_limits<int>::max() - 1 )
        throw std::invalid_argument(constraint);
    int64_t numerator = term1 - offset_y + (border ? border[0] : attr->border.y);
    if ( numerator % scale_y_d != 0 ) throw std::invalid_argument(constraint);
    if ( OH != numerator / scale_y_d + 1 ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_338aejy0aeqeg(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: RESIZE,
    static constexpr char constraint[] = "ERROR_IF(OW != idiv_check((IW - 1) * scale_x_n - offset_x + border_x, scale_x_d) + 1)";
    auto IW = op->Input(TensorUsage::IFM)->shape.Width();
    auto OW = op->Output(TensorUsage::OFM)->shape.Width();
    const auto *attr = op->Attribute<regor::resize_attr_t>();
    const auto scaleConn = op->Input(TensorUsage::Params0);
    const auto offsetConn = op->Input(TensorUsage::Params1);
    const auto borderConn = op->Input(TensorUsage::Params2);
    Shape scale = scaleConn ? GetShapeFromValues(scaleConn->tensor.get()) : Shape{};
    Shape offset = offsetConn ? GetShapeFromValues(offsetConn->tensor.get()) : Shape{};
    Shape border = borderConn ? GetShapeFromValues(borderConn->tensor.get()) : Shape{};
    // Compile time constant tensor attributes takes precedence over operator attributes
    auto scale_x_n = scale ? scale[2] : attr->scaleX.n;
    auto scale_x_d = scale ? scale[3] : attr->scaleX.d;
    if ( scale_x_n > (1 << 11) || scale_x_d >= 16 * scale_x_n ) throw std::invalid_argument(constraint);
    auto offset_x = offset ? offset[1] : attr->offset.x;
    if ( offset_x < -scale_x_n || offset_x >= 16 * scale_x_n ) throw std::invalid_argument(constraint);
    if ( IW < 1 || IW >= std::numeric_limits<int16_t>::max() || scale_x_n <= 0 || scale_x_d <= 0 )
        throw std::invalid_argument(constraint);
    int64_t term1 = (IW - 1LL) * scale_x_n;
    if ( term1 >= std::numeric_limits<int64_t>::max() - 2LL * std::numeric_limits<int>::max() )
        throw std::invalid_argument(constraint);
    int64_t numerator = term1 - offset_x + (border ? border[1] : attr->border.x);
    if ( numerator % scale_x_d != 0 ) throw std::invalid_argument(constraint);
    if ( OW != numerator / scale_x_d + 1 ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_2a4sjfbd544h5(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: RESCALE,
    static constexpr char constraint[] = "ERROR_IF(!is_same<in_t,i8_t>() && (!is_same<in_t,i16_t>() || input_unsigned == false) && input_zp != 0)";
    const auto attr = op->Attribute<regor::sign_attr_t>();
    const auto in_t = op->IFM(0)->Type();
    const auto input_zp = Scalar<int>(*op->Input(TensorUsage::Params2)->tensor);
    bool error = in_t != DataType::Int8 && (in_t != DataType::Int16 || !attr->input_unsigned) && input_zp != 0;
    if ( error ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_32ylwe00j5q2l(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: RESCALE,
    static constexpr char constraint[] = "ERROR_IF(!is_same<output_zp,i8_t>() && (!is_same<out_t,i16_t>() || output_unsigned == false) && output_zp != 0)";
    const auto attr = op->Attribute<regor::sign_attr_t>();
    const auto out_t = op->OFM()->Type();
    const auto output_zp = Scalar<int>(*op->Input(TensorUsage::Params3)->tensor);
    bool error = out_t != DataType::Int8 && (out_t != DataType::Int16 || !attr->output_unsigned) && output_zp != 0;
    if ( error ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_3uwlzew8kfq5w(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: RESCALE,
    static constexpr char constraint[] = "ERROR_IF(is_same<in_t,i16_t>() && input_unsigned == true && input_zp != 0 && input_zp != 32768)";
    const auto attr = op->Attribute<regor::sign_attr_t>();
    const auto in_t = op->IFM(0)->Type();
    const auto input_zp = Scalar<int>(*op->Input(TensorUsage::Params2)->tensor);
    // The scalar zero point tensor will be converted as int16_t,
    // change the check below since int16_t(-32768) == uint16_t(32768)
    bool error = in_t == DataType::Int16 && attr->input_unsigned && input_zp != 0 && input_zp != -32768;
    if ( error ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_1sxf726x838dv(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: RESCALE,
    static constexpr char constraint[] = "ERROR_IF(is_same<out_t,i16_t>() && output_unsigned == true && output_zp != 0 && output_zp != 32768)";
    const auto attr = op->Attribute<regor::sign_attr_t>();
    const auto out_t = op->OFM()->Type();
    const auto output_zp = Scalar<int>(*op->Input(TensorUsage::Params3)->tensor);
    // The scalar zero point tensor will be converted as int16_t,
    // change the check below since int16_t(-32768) == uint16_t(32768)
    bool error = out_t == DataType::Int16 && attr->output_unsigned && output_zp != 0 && output_zp != -32768;
    if ( error ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_2fl3he9sci345(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: RESCALE,
    static constexpr char constraint[] = "ERROR_IF(scale32 && is_same<in_t,i48_t>())";
    const auto attr = op->Attribute<regor::rescale_attr_t>();
    const auto in_t = op->IFM(0)->Type();
    if ( attr->scale32 && in_t == DataType::Int48 ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_1acxf2776vdap(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: RESCALE,
    static constexpr char constraint[] = "ERROR_IF(!scale32 && (rounding_mode == DOUBLE_ROUND))";
    const auto attr = op->Attribute<regor::rescale_attr_t>();
    if ( !attr->scale32 && attr->double_round ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_2ntycki2dof18(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: RESCALE,
    static constexpr char constraint[] = "ERROR_IF(input_unsigned && output_unsigned)";
    const auto attr = op->Attribute<regor::sign_attr_t>();
    if ( attr->input_unsigned && attr->output_unsigned ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_1yv98jo1xcmke(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: RESCALE,
    static constexpr char constraint[] = "ERROR_IF(is_same<out_t,i32_t>() && input_unsigned)";
    const auto attr = op->Attribute<regor::sign_attr_t>();
    const auto out_t = op->OFM()->Type();
    if ( out_t == DataType::Int32 && attr->input_unsigned ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_bkdiivlz937z(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: RESCALE,
    static constexpr char constraint[] = "ERROR_IF(is_same<in_t,i32_t>() && output_unsigned)";
    const auto attr = op->Attribute<regor::sign_attr_t>();
    const auto in_t = op->IFM(0)->Type();
    if ( in_t == DataType::Int32 && attr->output_unsigned ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_242iuwska81dr(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: RESCALE,
    static constexpr char constraint[] = "ERROR_IF(is_same<in_t,i48_t>() && output_unsigned)";
    const auto attr = op->Attribute<regor::sign_attr_t>();
    const auto in_t = op->IFM(0)->Type();
    if ( in_t == DataType::Int48 && attr->output_unsigned ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_2vooovn86b8fd(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: RESCALE,
    static constexpr char constraint[] = "ERROR_IF(is_same<in_t, i48_t> && input_unsigned)";
    const auto attr = op->Attribute<regor::sign_attr_t>();
    const auto in_t = op->IFM(0)->Type();
    if ( in_t == DataType::Int48 && attr->input_unsigned ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_107z2k4den74o(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: RESCALE,
    static constexpr char constraint[] = "ERROR_IF(is_same<in_t, i32_t> && input_unsigned)";
    const auto attr = op->Attribute<regor::sign_attr_t>();
    const auto in_t = op->IFM(0)->Type();
    if ( in_t == DataType::Int32 && attr->input_unsigned ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_38712gnuluf0u(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: RESCALE,
    static constexpr char constraint[] = "ERROR_IF(is_same<out_t, i32_t> && output_unsigned)";
    const auto attr = op->Attribute<regor::sign_attr_t>();
    const auto out_t = op->OFM()->Type();
    if ( out_t == DataType::Int32 && attr->output_unsigned ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_4alci0dog4gp(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: RESCALE,
    static constexpr char constraint[] = "ERROR_IF(per_channel && rank(input) < 1)";
    const auto attr = op->Attribute<regor::rescale_attr_t>();
    const auto rank_input = op->IFM(0)->StorageShape().Size();
    if ( attr->per_channel && rank_input < 1 ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_31ty7f0kcbfxg(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: RESCALE,
    static constexpr char constraint[] = "ERROR_IF(shapeCheck(shift, [NC], multiplier, [NC]))";
    const auto &shape = op->Output(TensorUsage::OFM)->shape;
    const auto &shiftShape = op->Input(TensorUsage::Params)->shape;
    const auto &multiplierShape = op->Input(TensorUsage::Params1)->shape;
    auto outRank = shape.Size();
    const auto *attr = op->Attribute<regor::rescale_attr_t>();
    auto NC = attr->per_channel ? (outRank > 0 ? shape[outRank - 1] : 1) : 1;
    if ( shiftShape[0] != NC || multiplierShape[0] != NC ) throw std::invalid_argument(constraint);  // NC
}

void ErrorIfCheck_3oet4aggtv528(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: CONST,
    // Would ideally check that the shape of the attibute "values" matches output shape, but that has already been
    // read in to the OFM buffer so no tensor exists. Instead, check that buffer has enough elements for the ofm.
    static constexpr char constraint[] = "ERROR_IF(rankCheck(output, values))";
    const auto &ofmConn = op->Output(TensorUsage::OFM);
    const auto bufferSize = ofmConn->tensor->View().Buffer()->Size();
    const auto storageSize = DataTypeStorageSizeBytes(ofmConn->tensor->Type(), ofmConn->shape.Elements());
    // TOSA tensors align to 8 bytes so can't check exact size
    // Instead, check that buffer is big enough to fill the OFM
    if ( bufferSize < storageSize ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_15kl5g5u1jrhq(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: COND_IF, WHILE_LOOP,
    static constexpr char constraint[] = "ERROR_IF(tosa_nesting_depth >= MAX_NESTING)";
    bool checkOk = true;
    checkOk = (op != nullptr);  // Can't implement this check with current validation code
    if ( !checkOk ) throw std::invalid_argument(constraint);
}

static bool ShapeListsMatch(const ordered_map<TensorUsage, TensorConnection> &A,
    const std::vector<std::shared_ptr<Tensor>> &B, bool skipFirst = false)
{
    auto bSize = B.size();
    if ( bSize > size_t(std::numeric_limits<int32_t>::max()) ) return false;
    int64_t sizeDiff = A.size() - static_cast<int32_t>(bSize);
    if ( sizeDiff != (skipFirst ? 1 : 0) ) return false;
    auto iterA = A.begin();
    auto iterB = B.begin();
    if ( skipFirst )
    {
        iterA++;
    }
    while ( iterA != A.end() )
    {
        if ( iterA->shape != (*iterB)->StorageShape() ) return false;
        iterA++;
        iterB++;
    }
    return true;
}

static bool ShapeListsMatch(const ordered_map<TensorUsage, TensorConnection> &A, const ordered_map<TensorUsage, TensorConnection> &B)
{
    if ( A.size() != B.size() ) return false;
    auto iterA = A.begin();
    auto iterB = B.begin();

    while ( iterA != A.end() )
    {
        if ( iterA->shape != iterB->shape ) return false;
        iterA++;
        iterB++;
    }
    return true;
}

void ErrorIfCheck_1bm39avugkqqd(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: COND_IF,
    static constexpr char constraint[] = "ERROR_IF(tensor_list_shape(input_list) != tosa_input_shape(then_graph))";
    const auto *then_graph = context.GetGraph(op->Attribute<regor::cond_attr_t>()->then_branch.c_str());
    if ( !ShapeListsMatch(op->Inputs(), then_graph->Inputs(), true) ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_3tv3oatlz37e2(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: COND_IF,
    static constexpr char constraint[] = "ERROR_IF(tensor_list_shape(input_list) != tosa_input_shape(else_graph))";
    const auto *else_graph = context.GetGraph(op->Attribute<regor::cond_attr_t>()->else_branch.c_str());
    if ( !ShapeListsMatch(op->Inputs(), else_graph->Inputs(), true) ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_n7biu53x2n6k(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: COND_IF,
    static constexpr char constraint[] = "ERROR_IF(tensor_list_shape(output_list) != tosa_output_shape(then_graph))";
    const auto *then_graph = context.GetGraph(op->Attribute<regor::cond_attr_t>()->then_branch.c_str());
    if ( !ShapeListsMatch(op->Outputs(), then_graph->Outputs()) ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_2fd4dk1zw032u(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: COND_IF,
    static constexpr char constraint[] = "ERROR_IF(tensor_list_shape(output_list) != tosa_output_shape(else_graph))";
    const auto *else_graph = context.GetGraph(op->Attribute<regor::cond_attr_t>()->else_branch.c_str());
    if ( !ShapeListsMatch(op->Outputs(), else_graph->Outputs()) ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_omgw2xdm6irr(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: COND_IF,
    static constexpr char constraint[] = "ERROR_IF(tensor_size(shape) != 1)";
    auto condSize = op->Input(TensorUsage::IFM)->shape.Elements();
    if ( condSize != 1 ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_2jyu87hs8upt4(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: WHILE_LOOP,
    static constexpr char constraint[] = "ERROR_IF(tensor_list_shape(input_list) != tensor_list_shape(output_list))";
    if ( !ShapeListsMatch(op->Inputs(), op->Outputs()) ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_12uu5ff3t3lv8(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: WHILE_LOOP,
    static constexpr char constraint[] = "ERROR_IF(tensor_list_shape(input_list) != tosa_input_shape(cond_graph))";
    const auto *cond_graph = context.GetGraph(op->Attribute<regor::while_attr_t>()->cond_branch.c_str());
    if ( !ShapeListsMatch(op->Inputs(), cond_graph->Inputs()) ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_3puzf7van5acf(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: WHILE_LOOP,
    static constexpr char constraint[] = "ERROR_IF(tensor_list_shape(input_list) != tosa_input_shape(body_graph))";
    const auto *body_graph = context.GetGraph(op->Attribute<regor::while_attr_t>()->body_branch.c_str());
    if ( !ShapeListsMatch(op->Inputs(), body_graph->Inputs()) ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_8tihij7a5ep0(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: WHILE_LOOP,
    static constexpr char constraint[] = "ERROR_IF(tensor_list_shape(input_list) != tosa_output_shape(body_graph))";
    const auto *body_graph = context.GetGraph(op->Attribute<regor::while_attr_t>()->body_branch.c_str());
    if ( !ShapeListsMatch(op->Inputs(), body_graph->Outputs()) ) throw std::invalid_argument(constraint);
}

void ErrorIfCheck_3lu68v2531bjz(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: WHILE_LOOP,
    static constexpr char constraint[] = "ERROR_IF(tensor_size(tosa_output_shape(cond_graph)) != 1)";
    const auto *cond_graph = context.GetGraph(op->Attribute<regor::while_attr_t>()->cond_branch.c_str());
    const auto &condOutputs = cond_graph->Outputs();
    if ( condOutputs.size() != 1 || condOutputs.front()->StorageShape().Elements() != 1 )
        throw std::invalid_argument(constraint);
}

void ErrorIfCheck_1fzl0zyxyd88z(const regor::Operation *op, [[maybe_unused]] const Context &context)
{
    // Operators: WHILE_LOOP,
    static constexpr char constraint[] = "ERROR_IF(tosa_output_type(cond_graph) != bool_t)";
    const auto *cond_graph = context.GetGraph(op->Attribute<regor::while_attr_t>()->cond_branch.c_str());
    const auto &condOutputs = cond_graph->Outputs();
    if ( condOutputs.size() != 1 ) throw std::invalid_argument(constraint);
    auto type = condOutputs.front()->Type();
    if ( type != DataType::Bool8 && type != DataType::Bool ) throw std::invalid_argument(constraint);
}

}  // namespace checks
}  // namespace validator
}  // namespace tosa
