* Copyright (c) 2026 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 tile_tiling_arch35.cpp
* \brief calc tiling for tile
*/
#include "tile_tiling_arch35.h"
#include "conversion/broadcast_to/op_host/arch35/broadcast_to_tiling_base.h"
#include "log/log.h"
#include "register/op_impl_registry.h"
#include "tiling/tiling_api.h"
#include "op_host/tiling_base_class.h"
#include "op_host/tiling_base_util.h"
#include "util/platform_util.h"
namespace optiling {
constexpr size_t TILE_MAX_DIM_NUM = 0x8;
template <typename T>
static std::string Shape2String(const T& shape)
{
std::ostringstream oss;
oss << "[";
if (shape.GetDimNum() > 0) {
for (size_t i = 0; i < shape.GetDimNum() - 1; ++i) {
oss << shape.GetDim(i) << ", ";
}
oss << shape.GetDim(shape.GetDimNum() - 1);
}
oss << "]";
return oss.str();
}
static ge::graphStatus CheckTileRule(const gert::TilingContext* context, const gert::Shape& inShape,
const gert::Shape& outShape)
{
auto outDimNum = outShape.GetDimNum();
if (inShape.GetDimNum() != outDimNum) {
std::string dimMsg = std::to_string(inShape.GetDimNum()) + " and " + std::to_string(outDimNum);
std::string reasonMsg = "The input and output shape dim num should be equal.";
OP_LOGE_FOR_INVALID_SHAPEDIMS_WITH_REASON(context->GetNodeName(), "x and y", dimMsg.c_str(), reasonMsg.c_str());
return ge::GRAPH_FAILED;
}
for (size_t i = 0; i < outDimNum; i++) {
if (outShape[i] < inShape[i] || outShape[i] % inShape[i] != 0) {
return ge::GRAPH_FAILED;
}
}
return ge::GRAPH_SUCCESS;
}
static void ConvertTileAxis2BroadcastToAxis(gert::Shape& inShape, gert::Shape& outShape)
{
gert::Shape newInShape;
gert::Shape newOutShape;
auto DimNum = inShape.GetDimNum();
for (size_t i = 0; i < DimNum; i++) {
newInShape.AppendDim(1);
newInShape.AppendDim(inShape[i]);
newOutShape.AppendDim(outShape[i] / inShape[i]);
newOutShape.AppendDim(inShape[i]);
}
inShape = newInShape;
outShape = newOutShape;
}
static ge::graphStatus GetShapeInfo(const gert::TilingContext* context, gert::Shape& inShape, gert::Shape& outShape)
{
auto xStorage = context->GetInputShape(0);
OP_CHECK_NULL_WITH_CONTEXT(context, xStorage);
inShape = Ops::Base::EnsureNotScalar(xStorage->GetStorageShape());
auto yStorage = context->GetOutputShape(0);
OP_CHECK_NULL_WITH_CONTEXT(context, yStorage);
outShape = Ops::Base::EnsureNotScalar(yStorage->GetStorageShape());
auto outDimNum = outShape.GetDimNum();
if (inShape.GetDimNum() > outDimNum) {
std::string dimMsg = std::to_string(inShape.GetDimNum()) + " and " + std::to_string(outDimNum);
std::string reasonMsg = "The input shape should not have more dimensions than output shape.";
OP_LOGE_FOR_INVALID_SHAPEDIMS_WITH_REASON(context->GetNodeName(), "x and y", dimMsg.c_str(), reasonMsg.c_str());
return ge::GRAPH_FAILED;
}
if (outDimNum > TILE_MAX_DIM_NUM) {
std::string dimMsg = std::to_string(outDimNum);
std::string reasonMsg = "The output dim num should not be greater than " + std::to_string(TILE_MAX_DIM_NUM) +
".";
OP_LOGE_FOR_INVALID_SHAPEDIM_WITH_REASON(context->GetNodeName(), "y", dimMsg.c_str(), reasonMsg.c_str());
return ge::GRAPH_FAILED;
}
brcto::AdjustShapesToSameDimNum(inShape, outDimNum);
if (inShape.GetShapeSize() == 0 || outShape.GetShapeSize() == 0) {
std::string shapeMsg = Shape2String(inShape) + " and " + Shape2String(outShape);
std::string reasonMsg = "The input or output shape must not be empty.";
OP_LOGE_FOR_INVALID_SHAPES_WITH_REASON(context->GetNodeName(), "x and y", shapeMsg.c_str(), reasonMsg.c_str());
return ge::GRAPH_FAILED;
}
if (CheckTileRule(context, inShape, outShape) != ge::GRAPH_SUCCESS) {
std::string shapeMsg = Shape2String(inShape) + " and " + Shape2String(outShape);
std::string reasonMsg = "The input and output shapes mismatch the broadcast rule.";
OP_LOGE_FOR_INVALID_SHAPES_WITH_REASON(context->GetNodeName(), "x and y", shapeMsg.c_str(), reasonMsg.c_str());
return ge::GRAPH_FAILED;
}
ConvertTileAxis2BroadcastToAxis(inShape, outShape);
OP_LOGI(context->GetNodeName(), "The broadcastTo input and output after conversion are: %s and %s",
Shape2String(inShape).c_str(), Shape2String(outShape).c_str());
if (brcto::DeleteOneSizeAxis(context, inShape, outShape) != ge::GRAPH_SUCCESS) {
std::string shapeMsg = Shape2String(inShape) + " and " + Shape2String(outShape);
std::string reasonMsg = "Failed to delete one size axes.";
OP_LOGE_FOR_INVALID_SHAPES_WITH_REASON(context->GetNodeName(), "x and y", shapeMsg.c_str(), reasonMsg.c_str());
return ge::GRAPH_FAILED;
}
OP_LOGI(context->GetNodeName(), "The reshaped input and output are: %s and %s", Shape2String(inShape).c_str(),
Shape2String(outShape).c_str());
if (brcto::MergeAxis(context, inShape, outShape) != ge::GRAPH_SUCCESS) {
std::string shapeMsg = Shape2String(inShape) + " and " + Shape2String(outShape);
std::string reasonMsg = "Failed to merge axes.";
OP_LOGE_FOR_INVALID_SHAPES_WITH_REASON(context->GetNodeName(), "x and y", shapeMsg.c_str(), reasonMsg.c_str());
return ge::GRAPH_FAILED;
}
OP_LOGI(context->GetNodeName(), "The merged input and output are: %s and %s", Shape2String(inShape).c_str(),
Shape2String(outShape).c_str());
return ge::GRAPH_SUCCESS;
}
ge::graphStatus Tiling4TileAscendC(gert::TilingContext* context, const gert::Shape* inShapePtr,
const gert::Shape* outShapePtr)
{
OP_CHECK_NULL_WITH_CONTEXT(context, inShapePtr);
OP_CHECK_NULL_WITH_CONTEXT(context, outShapePtr);
brcto::BroadcastToTilingAscendC brcToTiling(context, inShapePtr, outShapePtr);
if (brcToTiling.GetHardwareInfo<TileCompileInfo>() != ge::GRAPH_SUCCESS) {
std::string valueMsg = "unknown";
std::string reasonMsg = "BroadcastToTilingAscendC failed to get hardware info.";
OP_LOGE_FOR_INVALID_VALUE_WITH_REASON(context->GetNodeName(), "hardwareInfo", valueMsg.c_str(),
reasonMsg.c_str());
return ge::GRAPH_FAILED;
}
return brcToTiling.DoTiling();
}
static ge::graphStatus Tiling4Tile(gert::TilingContext* context)
{
auto compile_info = reinterpret_cast<const TileCompileInfo*>(context->GetCompileInfo());
OP_CHECK_NULL_WITH_CONTEXT(context, compile_info);
gert::Shape inShape;
gert::Shape outShape;
if (GetShapeInfo(context, inShape, outShape) != ge::GRAPH_SUCCESS) {
std::string shapeMsg = "unknown";
std::string reasonMsg = "Failed to get input or output shape.";
OP_LOGE_FOR_INVALID_SHAPE_WITH_REASON(context->GetNodeName(), "x or y", shapeMsg.c_str(), reasonMsg.c_str());
return ge::GRAPH_FAILED;
}
return Tiling4TileAscendC(context, &inShape, &outShape);
}
static ge::graphStatus TilingPrepare4Tile(gert::TilingParseContext* context)
{
OP_LOGD(context->GetNodeName(), "Enter TilingPrepare4Tile.");
auto compileInfo = context->GetCompiledInfo<TileCompileInfo>();
OP_CHECK_NULL_WITH_CONTEXT(context, compileInfo);
auto ret = FillSocCompileInfo(context, compileInfo);
if (ret != ge::GRAPH_SUCCESS) {
return ret;
}
OP_LOGD(context->GetNodeName(), "Exit TilingPrepare4Tile.");
return ge::GRAPH_SUCCESS;
}
IMPL_OP_OPTILING(Tile).Tiling(Tiling4Tile).TilingParse<TileCompileInfo>(TilingPrepare4Tile);
}