/**
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
 * CANN Open Software License Agreement Version 2.0 (the "License").
 * Please refer to the License for details. You may not use this file except in compliance with the License.
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
 * See LICENSE in the root of the software repository for the full text of the License.
 */

/*!
 * \file upsample_bicubic2d_aa_tiling.cpp
 * \brief
 */
#include <vector>
#include "register/op_impl_registry.h"
#include "register/tilingdata_base.h"
#include "tiling/tiling_api.h"
#include "tiling/platform/platform_ascendc.h"
#include "op_host/tiling_util.h"
#include "log/log.h"
#include "upsample_bicubic2d_aa_tiling.h"

namespace optiling {
constexpr uint32_t BEST_PERFORMANCE_SIZE_1 = 16;
constexpr uint32_t BEST_PERFORMANCE_SIZE_2 = 32;
constexpr uint32_t BEST_PERFORMANCE_SIZE_3 = 48;
constexpr uint32_t BEST_PERFORMANCE_SIZE_4 = 64;

constexpr uint32_t BEST_PERFORMANCE_SCALE_1 = 50;
constexpr uint32_t BEST_PERFORMANCE_SCALE_2 = 20;
constexpr uint32_t BEST_PERFORMANCE_SCALE_3 = 8;
constexpr uint32_t BEST_PERFORMANCE_SCALE_4 = 5;
constexpr float BICUBIC_SUPPORT_SIZE = 2.0;
constexpr uint32_t BUFFER_LEN = 2;
constexpr uint32_t H_INDEX = 2;
constexpr uint32_t W_INDEX = 3;
constexpr uint32_t MAX_ATTR_COUNT = 4;

constexpr uint64_t TILING_KEY_HALF = 1;
constexpr uint64_t TILING_KEY_FLOAT = 2;
constexpr uint64_t TILING_KEY_BF16 = 3;

constexpr uint64_t WORK_SPACE_SIZE = 32 * 1024 * 1024;
constexpr uint32_t BYTE_LEN_4 = 4;
constexpr uint32_t BYTE_LENGTH_2 = 2;
constexpr uint32_t ADDR_ALIGN_SIZE = 512;
constexpr uint8_t SCHEDULE_MODE = 1;

constexpr uint32_t DOUBLE_VALUE = 2;

class UpsampleBicubic2dAATiling {
public:
    explicit UpsampleBicubic2dAATiling(gert::TilingContext* context) : tilingContext(context) {};
    ge::graphStatus RunBigKernelTiling(gert::TilingContext* context);

private:
    void SetScale();
    void SetSliceSize();
    inline float ComputeScaleValue(int64_t inputSize, int64_t outputSize, bool alignCornersFlag,
                                   const float* scale) const;
    void GetWorkSpace(uint32_t needCoreNum);
    void GetOutputShape();
    uint8_t GetDataTypeSize() const;
    uint64_t GetTilingKeyVal() const;
    uint32_t GetNeedCoreNumWidth(uint32_t coreNumPlatform);
    uint32_t GetNeedCoreNumHeight(uint32_t coreNumPlatform);
    void FillTilingData();
    void GetTCubeTilingW();
    void GetTCubeTilingH();
    bool CheckShapes() const;

    template <typename T1, typename T2>
    inline T1 CeilA2B(T1 a, T2 b) const;

    template <typename T1>
    inline int32_t Ceil(T1 x) const;

private:
    int64_t sliceSize = 0;
    UpsampleBicubic2dAATilingData tilingData;
    gert::TilingContext* tilingContext = nullptr;
    ge::DataType dataType = ge::DT_UNDEFINED;
    uint16_t dataTypeSize = 0;
    gert::Shape inputShape;
    const bool* alignCorners = nullptr;
    const float* scaleH = nullptr;
    const float* scaleW = nullptr;
    float realScaleH = 0.0;
    float realScaleW = 0.0;
    const gert::ContinuousVector* outputSizeVevtor = nullptr;
    int32_t sliceStartListW[MAX_CORE_CONT] = {0};
    int32_t sliceEndListW[MAX_CORE_CONT] = {0};
    int32_t tailSliceStartListW[MAX_CORE_CONT] = {0};
    int32_t tailsliceEndListW[MAX_CORE_CONT] = {0};
    int32_t tailRowStartListW[MAX_CORE_CONT] = {0};
    int32_t tailRowEndListW[MAX_CORE_CONT] = {0};
    int32_t sliceStartListH[MAX_CORE_CONT] = {0};
    int32_t sliceEndListH[MAX_CORE_CONT] = {0};
    int32_t tailSliceStartListH[MAX_CORE_CONT] = {0};
    int32_t tailSliceEndListH[MAX_CORE_CONT] = {0};
    int32_t tailBatchStartListH[MAX_CORE_CONT] = {0};
    int32_t tailBatchEndListH[MAX_CORE_CONT] = {0};

    uint32_t needCoreNumW = 0;
    uint32_t needCoreNumH = 0;

    int32_t outputShapes[4] = {0};
    int32_t inputShapes[4] = {0};

    TCubeTiling matmulTilingW;
    TCubeTiling matmulTilinH;
    int32_t singleCoreKW = 0;
    int32_t singleCoreKH = 0;
};

void UpsampleBicubic2dAATiling::SetScale()
{
    const int64_t* outputSizeArray = reinterpret_cast<const int64_t*>(outputSizeVevtor->GetData());

    int64_t outputHeight = outputSizeArray[0];
    int64_t outputWidth = outputSizeArray[1];
    bool alignCornersFlag = *alignCorners;
    realScaleH = ComputeScaleValue(inputShape.GetDim(H_INDEX), outputHeight, alignCornersFlag, scaleH);
    realScaleW = ComputeScaleValue(inputShape.GetDim(W_INDEX), outputWidth, alignCornersFlag, scaleW);

    tilingData.set_scaleH(realScaleH);
    tilingData.set_scaleW(realScaleW);

    float supportW = (realScaleW >= 1.0) ? BICUBIC_SUPPORT_SIZE * realScaleW : BICUBIC_SUPPORT_SIZE;
    float supportH = (realScaleH >= 1.0) ? BICUBIC_SUPPORT_SIZE * realScaleH : BICUBIC_SUPPORT_SIZE;

    tilingData.set_supportW(supportW);
    tilingData.set_supportH(supportH);

    int16_t maxInterpSizeW = Ceil(supportW) * 2 + 1;
    int16_t maxInterpSizeH = Ceil(supportH) * 2 + 1;

    tilingData.set_maxInterpSizeW(maxInterpSizeW);
    tilingData.set_maxInterpSizeH(maxInterpSizeH);

    float invscaleW = 1.0;
    if (realScaleW > 1.0) {
        invscaleW = static_cast<float>(1.0 / realScaleW);
    }
    float invscaleH = 1.0;
    if (realScaleH > 1.0) {
        invscaleH = static_cast<float>(1.0 / realScaleH);
    }

    tilingData.set_invscaleW(invscaleW);
    tilingData.set_invscaleH(invscaleH);
}

inline float UpsampleBicubic2dAATiling::ComputeScaleValue(int64_t inputSize, int64_t outputSize, bool alignCornersFlag,
                                                          const float* scale) const
{
    if (alignCornersFlag) {
        if (outputSize > 1) {
            return static_cast<float>(inputSize - 1) / (outputSize - 1);
        } else {
            return static_cast<float>(0);
        }
    } else {
        if (inputSize == outputSize) {
            return 1.0;
        }
        return (scale != nullptr && *scale > 0) ? *scale : (static_cast<float>(inputSize) / outputSize);
    }
}

ge::graphStatus UpsampleBicubic2dAATiling::RunBigKernelTiling(gert::TilingContext* context)
{
    bool regBase = Ops::Cv::OpTiling::IsRegbaseSocVersion(context);
    if (regBase) {
        OP_LOGI(tilingContext->GetNodeName(), "enter Tiling4UpsampleBicubic2dAARegbase");
        return Tiling4UpsampleBicubic2dAARegbase(tilingContext);
    }

    const gert::RuntimeAttrs* attrs = tilingContext->GetAttrs();
    if (attrs == nullptr) {
        return ge::GRAPH_FAILED;
    }
    outputSizeVevtor = attrs->GetAttrPointer<gert::ContinuousVector>(0);
    OP_CHECK_IF(outputSizeVevtor == nullptr, OP_LOGE(tilingContext->GetNodeName(), "outputSizeVevtor == nullptr"),
                return ge::GRAPH_FAILED);
    alignCorners = attrs->GetAttrPointer<bool>(1);
    OP_CHECK_IF(alignCorners == nullptr, OP_LOGE(tilingContext->GetNodeName(), "alignCorners == nullptr"),
                return ge::GRAPH_FAILED);
    scaleH = attrs->GetAttrPointer<float>(H_INDEX);
    OP_CHECK_IF(scaleH == nullptr, OP_LOGE(tilingContext->GetNodeName(), "scaleH == nullptr"), return ge::GRAPH_FAILED);
    scaleW = attrs->GetAttrPointer<float>(W_INDEX);
    OP_CHECK_IF(scaleW == nullptr, OP_LOGE(tilingContext->GetNodeName(), "scaleW == nullptr"), return ge::GRAPH_FAILED);

    auto tempInputDesc = tilingContext->GetInputDesc(0);
    OP_CHECK_IF(tempInputDesc == nullptr, OP_LOGE(tilingContext->GetNodeName(), "InputDesc == nullptr"),
                return ge::GRAPH_FAILED);
    dataType = tempInputDesc->GetDataType();
    dataTypeSize = GetDataTypeSize();

    auto srcShape = tilingContext->GetInputShape(0);
    OP_CHECK_IF(srcShape == nullptr, OP_LOGE(tilingContext->GetNodeName(), "InputShape == nullptr"),
                return ge::GRAPH_FAILED);

    inputShape = srcShape->GetOriginShape();
    if (CheckShapes() == false) {
        return ge::GRAPH_FAILED;
    }

    tilingContext->SetTilingKey(GetTilingKeyVal());

    GetOutputShape();

    SetScale();

    SetSliceSize();

    auto compileInfo = reinterpret_cast<const UpsampleBicubic2dAACompileInfo*>(tilingContext->GetCompileInfo());
    OP_CHECK_IF(compileInfo == nullptr, OP_LOGE(tilingContext->GetNodeName(), "compileInfo == nullptr"),
                return ge::GRAPH_FAILED);
    uint32_t coreNumPlatForm = compileInfo->totalCoreNum;

    needCoreNumW = GetNeedCoreNumWidth(coreNumPlatForm);
    needCoreNumH = GetNeedCoreNumHeight(coreNumPlatForm);

    uint32_t needCoreNum = std::max(needCoreNumW, needCoreNumH);
    GetWorkSpace(needCoreNum);

    tilingContext->SetBlockDim(needCoreNum);

    GetTCubeTilingW();
    GetTCubeTilingH();

    FillTilingData();
    return ge::GRAPH_SUCCESS;
}

void UpsampleBicubic2dAATiling::SetSliceSize()
{
    auto maxScale = realScaleH > realScaleW ? realScaleH : realScaleW;
    if (maxScale <= BEST_PERFORMANCE_SCALE_4) {
        sliceSize = BEST_PERFORMANCE_SIZE_4;
    } else if (maxScale <= BEST_PERFORMANCE_SCALE_3) {
        sliceSize = BEST_PERFORMANCE_SIZE_3;
    } else if (maxScale <= BEST_PERFORMANCE_SCALE_2) {
        sliceSize = BEST_PERFORMANCE_SIZE_2;
    } else {
        sliceSize = BEST_PERFORMANCE_SIZE_1;
    }
    if (sliceSize > outputShapes[H_INDEX] || sliceSize > outputShapes[W_INDEX]) {
        sliceSize = BEST_PERFORMANCE_SIZE_1;
    }
    tilingData.set_sliceSize(sliceSize);
}

bool UpsampleBicubic2dAATiling::CheckShapes() const
{
    OP_CHECK_IF(inputShape.GetDimNum() != 4,
                OP_LOGE(tilingContext->GetNodeName(), "Input tensor dim num must equal to 4"), return false);

    const int64_t* outputSizeArray = reinterpret_cast<const int64_t*>(outputSizeVevtor->GetData());
    int64_t inputH = inputShape.GetDim(2);
    int64_t inputW = inputShape.GetDim(3);
    int64_t outH = outputSizeArray[0];
    int64_t outW = outputSizeArray[1];

    OP_CHECK_IF(
        !(inputH > 0 && inputW > 0 && outH > 0 && outW > 0),
        OP_LOGE(tilingContext->GetNodeName(),
                "Input and output sizes should greater than 0, but got input (H: %ld, W: %ld) output (H: %ld, W: %ld)",
                inputH, inputW, outH, outW),
        return false);

    return true;
}

void UpsampleBicubic2dAATiling::GetTCubeTilingW()
{
    auto mmDataType = static_cast<matmul_tiling::DataType>(dataType);
    matmul_tiling::MatmulApiTiling mmTilingW;
    mmTilingW.SetAType(matmul_tiling::TPosition::GM, matmul_tiling::CubeFormat::ND, mmDataType, false);
    mmTilingW.SetBType(matmul_tiling::TPosition::GM, matmul_tiling::CubeFormat::ND, mmDataType, false);
    mmTilingW.SetCType(matmul_tiling::TPosition::GM, matmul_tiling::CubeFormat::ND, mmDataType);
    int64_t totalM = static_cast<int64_t>(inputShapes[0]) * inputShapes[1] * inputShape[2];
    mmTilingW.SetShape(totalM, sliceSize, singleCoreKW);
    mmTilingW.SetOrgShape(totalM, outputShapes[3], inputShapes[3]);

    if (mmTilingW.GetTiling(tilingData.matmulTilingW) == -1) {
        return;
    }
}

void UpsampleBicubic2dAATiling::GetTCubeTilingH()
{
    auto mmDataType = static_cast<matmul_tiling::DataType>(dataType);
    matmul_tiling::MatmulApiTiling mmTilingH;
    mmTilingH.SetAType(matmul_tiling::TPosition::GM, matmul_tiling::CubeFormat::ND, mmDataType, true);
    mmTilingH.SetBType(matmul_tiling::TPosition::GM, matmul_tiling::CubeFormat::ND, mmDataType, false);
    mmTilingH.SetCType(matmul_tiling::TPosition::GM, matmul_tiling::CubeFormat::ND, mmDataType);
    mmTilingH.SetShape(sliceSize, outputShapes[3], singleCoreKH);
    mmTilingH.SetOrgShape(sliceSize, outputShapes[3], inputShape[2]);

    if (mmTilingH.GetTiling(tilingData.matmulTilingH) == -1) {
        return;
    }
}

void UpsampleBicubic2dAATiling::GetWorkSpace(uint32_t needCoreNum)
{
    size_t* workspaces = tilingContext->GetWorkspaceSizes(1);
    uint64_t intermediateMatrixSize = static_cast<uint64_t>(outputShapes[0]) * outputShapes[1] * inputShapes[2] *
                                      outputShapes[3] * dataTypeSize;

    singleCoreKW = Ceil(sliceSize * realScaleW) + Ceil(DOUBLE_VALUE * tilingData.get_supportW());
    uint32_t radioMatrixWSize = sliceSize * singleCoreKW * dataTypeSize;
    singleCoreKH = Ceil(sliceSize * realScaleH) + Ceil(DOUBLE_VALUE * tilingData.get_supportH());
    uint32_t radioMatrixHSize = sliceSize * singleCoreKH * dataTypeSize;
    uint32_t radioMatrixWorkspaceSize = std::max(radioMatrixWSize, radioMatrixHSize);
    intermediateMatrixSize = (intermediateMatrixSize + ADDR_ALIGN_SIZE - 1) / ADDR_ALIGN_SIZE * ADDR_ALIGN_SIZE;
    if (workspaces != nullptr) {
        workspaces[0] = intermediateMatrixSize +
                        static_cast<uint64_t>(radioMatrixWorkspaceSize) * needCoreNum * BUFFER_LEN + WORK_SPACE_SIZE;
    }

    tilingData.set_radioMatrixWSize(radioMatrixWSize);
    tilingData.set_radioMatrixHSize(radioMatrixHSize);
    tilingData.set_intermediateMatrixSize(intermediateMatrixSize);
}

void UpsampleBicubic2dAATiling::GetOutputShape()
{
    const int64_t* outputSizeArr = reinterpret_cast<const int64_t*>(outputSizeVevtor->GetData());
    for (int8_t i = 0; static_cast<uint32_t>(i) < MAX_ATTR_COUNT; i++) {
        inputShapes[i] = inputShape.GetDim(i);
        outputShapes[i] = inputShape.GetDim(i);
        if (i > 1) {
            outputShapes[i] = outputSizeArr[i - 2];
        }
    }
    tilingData.set_inputShapes(inputShapes);
    tilingData.set_outputShapes(outputShapes);
}

template <typename T1, typename T2>
inline auto UpsampleBicubic2dAATiling::CeilA2B(T1 a, T2 b) const -> T1
{
    if (b != 0) {
        return (a + b - 1) / b;
    } else {
        return a;
    }
}

template <typename T1>
inline int32_t UpsampleBicubic2dAATiling::Ceil(T1 x) const
{
    int32_t floorX = int32_t(x);
    float closeTo0 = float(1e-6);
    bool equalFlag = false;
    if (x > floorX) {
        equalFlag = (x - floorX < closeTo0) ? true : false;
    } else {
        equalFlag = (floorX - x < closeTo0) ? true : false;
    }
    if (equalFlag) {
        return floorX;
    }
    return floorX + 1;
}

uint8_t UpsampleBicubic2dAATiling::GetDataTypeSize() const
{
    switch (dataType) {
        case ge::DT_FLOAT:
            return BYTE_LEN_4;
        case ge::DT_FLOAT16:
            return BYTE_LENGTH_2;
        case ge::DT_BF16:
            return BYTE_LENGTH_2;
        default:
            return BYTE_LEN_4;
    }
}

uint64_t UpsampleBicubic2dAATiling::GetTilingKeyVal() const
{
    switch (dataType) {
        case ge::DT_FLOAT16:
            return TILING_KEY_HALF;
        case ge::DT_BF16:
            return TILING_KEY_BF16;
        case ge::DT_FLOAT:
            return TILING_KEY_FLOAT;
        default:
            return 0;
    }
}

uint32_t UpsampleBicubic2dAATiling::GetNeedCoreNumWidth(uint32_t coreNumPlatform)
{
    if (coreNumPlatform == 0) {
        return 0;
    }
    int64_t outputSize = outputShapes[3];
    int64_t sliceCount = CeilA2B(outputSize, sliceSize);
    int64_t eachCoreSliceNum = sliceCount / coreNumPlatform;
    int64_t remainder = sliceCount % coreNumPlatform;

    int64_t inputH = static_cast<int64_t>(inputShapes[0]) * inputShapes[1] * inputShapes[2];

    int64_t minAvergingRows = sliceSize * 2 / dataTypeSize;
    int64_t groupCore = 0;
    if (remainder > 0) {
        groupCore = coreNumPlatform / remainder;
    }
    int64_t tailAvergingRows = std::max(CeilA2B(inputH, groupCore), minAvergingRows);
    groupCore = std::min(groupCore, CeilA2B(inputH, tailAvergingRows));

    int64_t needCoreNum = 0;

    int64_t tailStartSliceNum = eachCoreSliceNum * coreNumPlatform;
    for (uint32_t coreIndex = 0; coreIndex < coreNumPlatform; coreIndex++) {
        sliceStartListW[coreIndex] = coreIndex * eachCoreSliceNum * sliceSize;
        sliceEndListW[coreIndex] = (std::min((coreIndex + 1) * eachCoreSliceNum, sliceCount)) * sliceSize;

        if (groupCore == 0) {
            continue;
        }
        int64_t groupIndex = coreIndex / groupCore;
        if (groupIndex < remainder) {
            tailSliceStartListW[coreIndex] = (tailStartSliceNum + groupIndex) * sliceSize;
            tailsliceEndListW[coreIndex] = std::min(tailSliceStartListW[coreIndex] + sliceSize,
                                                    static_cast<int64_t>(outputSize));
            int64_t coreIndexInGroup = coreIndex % groupCore;
            tailRowStartListW[coreIndex] = coreIndexInGroup * tailAvergingRows;
            tailRowEndListW[coreIndex] = std::min(tailRowStartListW[coreIndex] + tailAvergingRows,
                                                  static_cast<int64_t>(inputH));
            needCoreNum++;
        }
    }

    if (eachCoreSliceNum > 0) {
        needCoreNum = coreNumPlatform;
    }

    return needCoreNum;
}

uint32_t UpsampleBicubic2dAATiling::GetNeedCoreNumHeight(uint32_t coreNumPlatform)
{
    if (coreNumPlatform == 0) {
        return 0;
    }
    int64_t outputSize = outputShapes[2];
    int64_t sliceCount = CeilA2B(outputSize, sliceSize);
    int64_t eachCoreSliceNum = sliceCount / coreNumPlatform;
    int64_t remainder = sliceCount % coreNumPlatform;

    int64_t inputBatch = static_cast<int64_t>(inputShapes[0]) * inputShapes[1];

    int64_t groupCoreNum = 0;
    if (remainder > 0) {
        groupCoreNum = coreNumPlatform / remainder;
    }
    int64_t tailAvergingBatch = CeilA2B(inputBatch, groupCoreNum);
    groupCoreNum = std::min(groupCoreNum, CeilA2B(inputBatch, tailAvergingBatch));

    int64_t needCoreNum = 0;

    int64_t tailStartSliceNum = eachCoreSliceNum * coreNumPlatform;
    for (uint32_t coreIndex = 0; coreIndex < coreNumPlatform; coreIndex++) {
        sliceStartListH[coreIndex] = coreIndex * eachCoreSliceNum * sliceSize;
        sliceEndListH[coreIndex] = (std::min((coreIndex + 1) * eachCoreSliceNum, sliceCount)) * sliceSize;

        if (groupCoreNum == 0) {
            continue;
        }
        int64_t groupIndex = coreIndex / groupCoreNum;
        if (groupIndex < remainder) {
            tailSliceStartListH[coreIndex] = (tailStartSliceNum + groupIndex) * sliceSize;
            tailSliceEndListH[coreIndex] = std::min(tailSliceStartListH[coreIndex] + sliceSize,
                                                    static_cast<int64_t>(outputSize));
            int64_t coreIndexInGroup = coreIndex % groupCoreNum;
            tailBatchStartListH[coreIndex] = coreIndexInGroup * tailAvergingBatch;
            tailBatchEndListH[coreIndex] = std::min(tailBatchStartListH[coreIndex] + tailAvergingBatch,
                                                    static_cast<int64_t>(inputBatch));
            needCoreNum++;
        }
    }

    if (eachCoreSliceNum > 0) {
        needCoreNum = coreNumPlatform;
    }

    return needCoreNum;
}

void UpsampleBicubic2dAATiling::FillTilingData()
{
    tilingData.set_needCoreNumW(needCoreNumW);
    tilingData.set_needCoreNumH(needCoreNumH);
    tilingData.set_sliceStartListW(sliceStartListW);
    tilingData.set_sliceEndListW(sliceEndListW);
    tilingData.set_tailSliceStartListW(tailSliceStartListW);
    tilingData.set_tailSliceEndListW(tailsliceEndListW);
    tilingData.set_tailRowStartListW(tailRowStartListW);
    tilingData.set_tailRowEndListW(tailRowEndListW);

    tilingData.set_sliceStartListH(sliceStartListH);
    tilingData.set_sliceEndListH(sliceEndListH);
    tilingData.set_tailSliceStartListH(tailSliceStartListH);
    tilingData.set_tailSliceEndListH(tailSliceEndListH);
    tilingData.set_tailBatchStartListH(tailBatchStartListH);
    tilingData.set_tailBatchEndListH(tailBatchEndListH);

    tilingData.SaveToBuffer(tilingContext->GetRawTilingData()->GetData(),
                            tilingContext->GetRawTilingData()->GetCapacity());
    tilingContext->GetRawTilingData()->SetDataSize(tilingData.GetDataSize());
}

static ge::graphStatus Tiling4UpsampleBicubic2dAA(gert::TilingContext* context)
{
    UpsampleBicubic2dAATiling tilingObject(context);
    context->SetScheduleMode(SCHEDULE_MODE);
    return tilingObject.RunBigKernelTiling(context);
}

static ge::graphStatus TilingPrepare4Bicubic2DAA(gert::TilingParseContext* context)
{
    auto compileInfo = context->GetCompiledInfo<UpsampleBicubic2dAACompileInfo>();
    OP_CHECK_NULL_WITH_CONTEXT(context, compileInfo);
    auto platformInfo = context->GetPlatformInfo();
    auto ascendcPlatform = platform_ascendc::PlatformAscendC(platformInfo);
    compileInfo->totalCoreNum = ascendcPlatform.GetCoreNumAic();

    OP_CHECK_IF(compileInfo->totalCoreNum <= 0,
                OP_LOGE(context->GetNodeName(), "UpsampleBicubic2dAA GetHardwareInfo Failed, vectorCoreNum:%u",
                        compileInfo->totalCoreNum),
                return ge::GRAPH_FAILED);
    return ge::GRAPH_SUCCESS;
}

IMPL_OP_OPTILING(UpsampleBicubic2dAA)
    .Tiling(Tiling4UpsampleBicubic2dAA)
    .TilingParse<UpsampleBicubic2dAACompileInfo>(TilingPrepare4Bicubic2DAA);

} // namespace optiling