This commit is contained in:
@@ -8,6 +8,7 @@ add_pim_library(OMPimCommon
|
||||
IR/IndexingUtils.cpp
|
||||
IR/LoopUtils.cpp
|
||||
IR/ShapeUtils.cpp
|
||||
IR/ShapingUtils.cpp
|
||||
IR/SubviewUtils.cpp
|
||||
IR/TensorSliceUtils.cpp
|
||||
IR/WeightUtils.cpp
|
||||
|
||||
@@ -31,7 +31,7 @@ static FailureOr<int64_t> ceilDivSigned(int64_t lhs, int64_t rhs) {
|
||||
}
|
||||
|
||||
Value createOrFoldAffineApply(
|
||||
RewriterBase& rewriter, Location loc, AffineMap map, ValueRange operands, Operation* constantAnchor) {
|
||||
OpBuilder& builder, Location loc, AffineMap map, ValueRange operands, Operation* constantAnchor) {
|
||||
assert(constantAnchor && "expected a valid constant anchor");
|
||||
assert(map.getNumResults() == 1 && "affine.apply expects a single-result affine map");
|
||||
|
||||
@@ -40,91 +40,91 @@ Value createOrFoldAffineApply(
|
||||
for (Value operand : operands) {
|
||||
std::optional<int64_t> constantValue = matchConstantIndexValue(operand);
|
||||
if (!constantValue)
|
||||
return affine::AffineApplyOp::create(rewriter, loc, map, operands).getResult();
|
||||
operandConstants.push_back(rewriter.getIndexAttr(*constantValue));
|
||||
return affine::AffineApplyOp::create(builder, loc, map, operands).getResult();
|
||||
operandConstants.push_back(builder.getIndexAttr(*constantValue));
|
||||
}
|
||||
|
||||
SmallVector<Attribute> foldedResults;
|
||||
if (succeeded(map.constantFold(operandConstants, foldedResults)) && foldedResults.size() == 1)
|
||||
if (auto constantResult = dyn_cast<IntegerAttr>(foldedResults.front()))
|
||||
return getOrCreateIndexConstant(rewriter, constantAnchor, constantResult.getInt());
|
||||
return getOrCreateIndexConstant(builder, constantAnchor, constantResult.getInt());
|
||||
|
||||
return affine::AffineApplyOp::create(rewriter, loc, map, operands).getResult();
|
||||
return affine::AffineApplyOp::create(builder, loc, map, operands).getResult();
|
||||
}
|
||||
|
||||
Value createOrFoldAffineApply(
|
||||
RewriterBase& rewriter, Location loc, AffineExpr expr, ValueRange dims, Operation* constantAnchor) {
|
||||
OpBuilder& builder, Location loc, AffineExpr expr, ValueRange dims, Operation* constantAnchor) {
|
||||
AffineMap map = AffineMap::get(/*dimCount=*/dims.size(), /*symbolCount=*/0, expr);
|
||||
return createOrFoldAffineApply(rewriter, loc, map, dims, constantAnchor);
|
||||
return createOrFoldAffineApply(builder, loc, map, dims, constantAnchor);
|
||||
}
|
||||
|
||||
Value affineMulConst(RewriterBase& rewriter, Location loc, Value value, int64_t multiplier, Operation* constantAnchor) {
|
||||
Value affineMulConst(OpBuilder& builder, Location loc, Value value, int64_t multiplier, Operation* constantAnchor) {
|
||||
assert(constantAnchor && "expected a valid constant anchor");
|
||||
if (multiplier == 0)
|
||||
return getOrCreateIndexConstant(rewriter, constantAnchor, 0);
|
||||
return getOrCreateIndexConstant(builder, constantAnchor, 0);
|
||||
if (multiplier == 1)
|
||||
return value;
|
||||
|
||||
AffineExpr d0 = getAffineDimExpr(0, rewriter.getContext());
|
||||
return createOrFoldAffineApply(rewriter, loc, d0 * multiplier, ValueRange {value}, constantAnchor);
|
||||
AffineExpr d0 = getAffineDimExpr(0, builder.getContext());
|
||||
return createOrFoldAffineApply(builder, loc, d0 * multiplier, ValueRange {value}, constantAnchor);
|
||||
}
|
||||
|
||||
Value affineAddConst(RewriterBase& rewriter, Location loc, Value value, int64_t offset, Operation* constantAnchor) {
|
||||
Value affineAddConst(OpBuilder& builder, Location loc, Value value, int64_t offset, Operation* constantAnchor) {
|
||||
assert(constantAnchor && "expected a valid constant anchor");
|
||||
if (offset == 0)
|
||||
return value;
|
||||
|
||||
AffineExpr d0 = getAffineDimExpr(0, rewriter.getContext());
|
||||
return createOrFoldAffineApply(rewriter, loc, d0 + offset, ValueRange {value}, constantAnchor);
|
||||
AffineExpr d0 = getAffineDimExpr(0, builder.getContext());
|
||||
return createOrFoldAffineApply(builder, loc, d0 + offset, ValueRange {value}, constantAnchor);
|
||||
}
|
||||
|
||||
Value affineModConst(RewriterBase& rewriter, Location loc, Value value, int64_t divisor, Operation* constantAnchor) {
|
||||
Value affineModConst(OpBuilder& builder, Location loc, Value value, int64_t divisor, Operation* constantAnchor) {
|
||||
assert(constantAnchor && "expected a valid constant anchor");
|
||||
assert(divisor > 0 && "expected a positive affine.mod divisor");
|
||||
if (divisor == 1)
|
||||
return getOrCreateIndexConstant(rewriter, constantAnchor, 0);
|
||||
return getOrCreateIndexConstant(builder, constantAnchor, 0);
|
||||
|
||||
AffineExpr d0 = getAffineDimExpr(0, rewriter.getContext());
|
||||
return createOrFoldAffineApply(rewriter, loc, d0 % divisor, ValueRange {value}, constantAnchor);
|
||||
AffineExpr d0 = getAffineDimExpr(0, builder.getContext());
|
||||
return createOrFoldAffineApply(builder, loc, d0 % divisor, ValueRange {value}, constantAnchor);
|
||||
}
|
||||
|
||||
Value affineFloorDivConst(
|
||||
RewriterBase& rewriter, Location loc, Value value, int64_t divisor, Operation* constantAnchor) {
|
||||
OpBuilder& builder, Location loc, Value value, int64_t divisor, Operation* constantAnchor) {
|
||||
assert(constantAnchor && "expected a valid constant anchor");
|
||||
assert(divisor > 0 && "expected a positive affine.floor_div divisor");
|
||||
if (divisor == 1)
|
||||
return value;
|
||||
|
||||
AffineExpr d0 = getAffineDimExpr(0, rewriter.getContext());
|
||||
return createOrFoldAffineApply(rewriter, loc, d0.floorDiv(divisor), ValueRange {value}, constantAnchor);
|
||||
AffineExpr d0 = getAffineDimExpr(0, builder.getContext());
|
||||
return createOrFoldAffineApply(builder, loc, d0.floorDiv(divisor), ValueRange {value}, constantAnchor);
|
||||
}
|
||||
|
||||
Value affineAddModConst(
|
||||
RewriterBase& rewriter, Location loc, Value value, int64_t offset, int64_t divisor, Operation* constantAnchor) {
|
||||
OpBuilder& builder, Location loc, Value value, int64_t offset, int64_t divisor, Operation* constantAnchor) {
|
||||
assert(constantAnchor && "expected a valid constant anchor");
|
||||
assert(divisor > 0 && "expected a positive affine.mod divisor");
|
||||
if (divisor == 1)
|
||||
return getOrCreateIndexConstant(rewriter, constantAnchor, 0);
|
||||
return getOrCreateIndexConstant(builder, constantAnchor, 0);
|
||||
|
||||
AffineExpr d0 = getAffineDimExpr(0, rewriter.getContext());
|
||||
AffineExpr d0 = getAffineDimExpr(0, builder.getContext());
|
||||
AffineExpr expr = d0;
|
||||
if (offset != 0)
|
||||
expr = expr + offset;
|
||||
return createOrFoldAffineApply(rewriter, loc, expr % divisor, ValueRange {value}, constantAnchor);
|
||||
return createOrFoldAffineApply(builder, loc, expr % divisor, ValueRange {value}, constantAnchor);
|
||||
}
|
||||
|
||||
Value affineAddFloorDivConst(
|
||||
RewriterBase& rewriter, Location loc, Value value, int64_t offset, int64_t divisor, Operation* constantAnchor) {
|
||||
OpBuilder& builder, Location loc, Value value, int64_t offset, int64_t divisor, Operation* constantAnchor) {
|
||||
assert(constantAnchor && "expected a valid constant anchor");
|
||||
assert(divisor > 0 && "expected a positive affine.floor_div divisor");
|
||||
if (divisor == 1)
|
||||
return offset == 0 ? value : affineAddConst(rewriter, loc, value, offset, constantAnchor);
|
||||
return offset == 0 ? value : affineAddConst(builder, loc, value, offset, constantAnchor);
|
||||
|
||||
AffineExpr d0 = getAffineDimExpr(0, rewriter.getContext());
|
||||
AffineExpr d0 = getAffineDimExpr(0, builder.getContext());
|
||||
AffineExpr expr = d0;
|
||||
if (offset != 0)
|
||||
expr = expr + offset;
|
||||
return createOrFoldAffineApply(rewriter, loc, expr.floorDiv(divisor), ValueRange {value}, constantAnchor);
|
||||
return createOrFoldAffineApply(builder, loc, expr.floorDiv(divisor), ValueRange {value}, constantAnchor);
|
||||
}
|
||||
|
||||
FailureOr<int64_t> evaluateAffineExpr(AffineExpr expr, ArrayRef<int64_t> dims, ArrayRef<int64_t> symbols) {
|
||||
|
||||
@@ -11,50 +11,50 @@ namespace onnx_mlir {
|
||||
|
||||
using IndexValueResolver = llvm::function_ref<llvm::FailureOr<int64_t>(mlir::Value)>;
|
||||
|
||||
mlir::Value createOrFoldAffineApply(mlir::RewriterBase& rewriter,
|
||||
mlir::Value createOrFoldAffineApply(mlir::OpBuilder& builder,
|
||||
mlir::Location loc,
|
||||
mlir::AffineMap map,
|
||||
mlir::ValueRange operands,
|
||||
mlir::Operation* constantAnchor);
|
||||
|
||||
mlir::Value createOrFoldAffineApply(mlir::RewriterBase& rewriter,
|
||||
mlir::Value createOrFoldAffineApply(mlir::OpBuilder& builder,
|
||||
mlir::Location loc,
|
||||
mlir::AffineExpr expr,
|
||||
mlir::ValueRange dims,
|
||||
mlir::Operation* constantAnchor);
|
||||
|
||||
mlir::Value affineMulConst(mlir::RewriterBase& rewriter,
|
||||
mlir::Value affineMulConst(mlir::OpBuilder& builder,
|
||||
mlir::Location loc,
|
||||
mlir::Value value,
|
||||
int64_t multiplier,
|
||||
mlir::Operation* constantAnchor);
|
||||
|
||||
mlir::Value affineAddConst(mlir::RewriterBase& rewriter,
|
||||
mlir::Value affineAddConst(mlir::OpBuilder& builder,
|
||||
mlir::Location loc,
|
||||
mlir::Value value,
|
||||
int64_t offset,
|
||||
mlir::Operation* constantAnchor);
|
||||
|
||||
mlir::Value affineModConst(mlir::RewriterBase& rewriter,
|
||||
mlir::Value affineModConst(mlir::OpBuilder& builder,
|
||||
mlir::Location loc,
|
||||
mlir::Value value,
|
||||
int64_t divisor,
|
||||
mlir::Operation* constantAnchor);
|
||||
|
||||
mlir::Value affineFloorDivConst(mlir::RewriterBase& rewriter,
|
||||
mlir::Value affineFloorDivConst(mlir::OpBuilder& builder,
|
||||
mlir::Location loc,
|
||||
mlir::Value value,
|
||||
int64_t divisor,
|
||||
mlir::Operation* constantAnchor);
|
||||
|
||||
mlir::Value affineAddModConst(mlir::RewriterBase& rewriter,
|
||||
mlir::Value affineAddModConst(mlir::OpBuilder& builder,
|
||||
mlir::Location loc,
|
||||
mlir::Value value,
|
||||
int64_t offset,
|
||||
int64_t divisor,
|
||||
mlir::Operation* constantAnchor);
|
||||
|
||||
mlir::Value affineAddFloorDivConst(mlir::RewriterBase& rewriter,
|
||||
mlir::Value affineAddFloorDivConst(mlir::OpBuilder& builder,
|
||||
mlir::Location loc,
|
||||
mlir::Value value,
|
||||
int64_t offset,
|
||||
|
||||
@@ -49,7 +49,7 @@ Value getOrCreateConstant(OperationFolder& folder, Operation* anchorOp, Attribut
|
||||
return folder.getOrCreateConstant(hostBlock, arithDialect, value, type);
|
||||
}
|
||||
|
||||
Value getOrCreateConstant(RewriterBase& rewriter, Operation* anchorOp, Attribute value, Type type) {
|
||||
Value getOrCreateConstant(OpBuilder& builder, Operation* anchorOp, Attribute value, Type type) {
|
||||
assert(anchorOp && "expected a valid anchor operation");
|
||||
Block* hostBlock = getConstantInsertionBlock(anchorOp);
|
||||
for (Operation& op : *hostBlock) {
|
||||
@@ -59,9 +59,16 @@ Value getOrCreateConstant(RewriterBase& rewriter, Operation* anchorOp, Attribute
|
||||
return constantOp.getResult();
|
||||
}
|
||||
|
||||
OpBuilder::InsertionGuard guard(rewriter);
|
||||
rewriter.setInsertionPointToStart(hostBlock);
|
||||
return arith::ConstantOp::create(rewriter, anchorOp->getLoc(), type, cast<TypedAttr>(value)).getResult();
|
||||
OpBuilder::InsertionGuard guard(builder);
|
||||
builder.setInsertionPointToStart(hostBlock);
|
||||
return arith::ConstantOp::create(builder, anchorOp->getLoc(), type, cast<TypedAttr>(value)).getResult();
|
||||
}
|
||||
|
||||
Value createConstantAtHostBlockStart(OpBuilder& builder, Operation* anchorOp, TypedAttr value) {
|
||||
assert(anchorOp && "expected a valid anchor operation");
|
||||
OpBuilder::InsertionGuard guard(builder);
|
||||
builder.setInsertionPointToStart(getConstantInsertionBlock(anchorOp));
|
||||
return arith::ConstantOp::create(builder, anchorOp->getLoc(), value).getResult();
|
||||
}
|
||||
|
||||
Value getOrCreateConstantLike(OperationFolder& folder, arith::ConstantOp constantOp) {
|
||||
@@ -73,9 +80,8 @@ Value getOrCreateIndexConstant(OperationFolder& folder, Operation* anchorOp, int
|
||||
return getOrCreateConstant(folder, anchorOp, builder.getIndexAttr(value), builder.getIndexType());
|
||||
}
|
||||
|
||||
Value getOrCreateIndexConstant(RewriterBase& rewriter, Operation* anchorOp, int64_t value) {
|
||||
Builder builder(anchorOp->getContext());
|
||||
return getOrCreateConstant(rewriter, anchorOp, builder.getIndexAttr(value), builder.getIndexType());
|
||||
Value getOrCreateIndexConstant(OpBuilder& builder, Operation* anchorOp, int64_t value) {
|
||||
return getOrCreateConstant(builder, anchorOp, builder.getIndexAttr(value), builder.getIndexType());
|
||||
}
|
||||
|
||||
void hoistAndUniquifyIndexConstants(func::FuncOp funcOp, RewriterBase& rewriter) {
|
||||
|
||||
@@ -16,13 +16,16 @@ mlir::Value
|
||||
getOrCreateConstant(mlir::OperationFolder& folder, mlir::Operation* anchorOp, mlir::Attribute value, mlir::Type type);
|
||||
|
||||
mlir::Value
|
||||
getOrCreateConstant(mlir::RewriterBase& rewriter, mlir::Operation* anchorOp, mlir::Attribute value, mlir::Type type);
|
||||
getOrCreateConstant(mlir::OpBuilder& builder, mlir::Operation* anchorOp, mlir::Attribute value, mlir::Type type);
|
||||
|
||||
mlir::Value
|
||||
createConstantAtHostBlockStart(mlir::OpBuilder& builder, mlir::Operation* anchorOp, mlir::TypedAttr value);
|
||||
|
||||
mlir::Value getOrCreateConstantLike(mlir::OperationFolder& folder, mlir::arith::ConstantOp constantOp);
|
||||
|
||||
mlir::Value getOrCreateIndexConstant(mlir::OperationFolder& folder, mlir::Operation* anchorOp, int64_t value);
|
||||
|
||||
mlir::Value getOrCreateIndexConstant(mlir::RewriterBase& rewriter, mlir::Operation* anchorOp, int64_t value);
|
||||
mlir::Value getOrCreateIndexConstant(mlir::OpBuilder& builder, mlir::Operation* anchorOp, int64_t value);
|
||||
|
||||
void hoistAndUniquifyIndexConstants(mlir::func::FuncOp funcOp, mlir::RewriterBase& rewriter);
|
||||
|
||||
|
||||
@@ -36,9 +36,10 @@ bool isCoreStaticAddressOp(mlir::Operation* op) {
|
||||
|
||||
mlir::LogicalResult
|
||||
walkPimCoreBlock(mlir::Block& block,
|
||||
const StaticValueKnowledge& knowledge,
|
||||
const StaticValueKnowledge& initialKnowledge,
|
||||
llvm::function_ref<mlir::LogicalResult(mlir::Operation&, const StaticValueKnowledge&)> callback) {
|
||||
bool hasFailure = false;
|
||||
StaticValueKnowledge knowledge = initialKnowledge;
|
||||
for (mlir::Operation& op : block) {
|
||||
if (mlir::isa<pim::PimHaltOp, mlir::scf::YieldOp>(op) || isCoreStaticAddressOp(&op))
|
||||
continue;
|
||||
@@ -89,6 +90,27 @@ walkPimCoreBlock(mlir::Block& block,
|
||||
continue;
|
||||
}
|
||||
|
||||
if (auto switchOp = mlir::dyn_cast<mlir::scf::IndexSwitchOp>(op)) {
|
||||
auto selector = resolveIndexValue(switchOp.getArg(), knowledge);
|
||||
if (failed(selector)) {
|
||||
switchOp.emitOpError("requires a statically evaluable scf.index_switch selector for PIM codegen");
|
||||
hasFailure = true;
|
||||
continue;
|
||||
}
|
||||
mlir::Region* selected = &switchOp.getDefaultRegion();
|
||||
for (auto [caseValue, caseRegion] : llvm::zip(switchOp.getCases(), switchOp.getCaseRegions()))
|
||||
if (caseValue == *selector) {
|
||||
selected = &caseRegion;
|
||||
break;
|
||||
}
|
||||
if (failed(walkPimCoreBlock(selected->front(), knowledge, callback)))
|
||||
hasFailure = true;
|
||||
auto yield = mlir::cast<mlir::scf::YieldOp>(selected->front().getTerminator());
|
||||
for (auto [result, yielded] : llvm::zip(switchOp.getResults(), yield.getOperands()))
|
||||
knowledge.aliases[result] = resolveLoopCarriedAlias(yielded, knowledge);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (failed(callback(op, knowledge)))
|
||||
hasFailure = true;
|
||||
}
|
||||
@@ -97,9 +119,10 @@ walkPimCoreBlock(mlir::Block& block,
|
||||
|
||||
mlir::LogicalResult walkPimCoreBlockStructurally(
|
||||
mlir::Block& block,
|
||||
const StaticValueKnowledge& knowledge,
|
||||
const StaticValueKnowledge& initialKnowledge,
|
||||
llvm::function_ref<mlir::LogicalResult(mlir::Operation&, const StaticValueKnowledge&)> callback) {
|
||||
bool hasFailure = false;
|
||||
StaticValueKnowledge knowledge = initialKnowledge;
|
||||
for (mlir::Operation& op : block) {
|
||||
if (mlir::isa<pim::PimHaltOp, mlir::scf::YieldOp>(op) || isCoreStaticAddressOp(&op))
|
||||
continue;
|
||||
@@ -159,6 +182,28 @@ mlir::LogicalResult walkPimCoreBlockStructurally(
|
||||
continue;
|
||||
}
|
||||
|
||||
if (auto switchOp = mlir::dyn_cast<mlir::scf::IndexSwitchOp>(op)) {
|
||||
auto selector = resolveIndexValue(switchOp.getArg(), knowledge);
|
||||
if (failed(selector)) {
|
||||
switchOp.emitOpError("requires a statically evaluable scf.index_switch selector for PIM verification");
|
||||
hasFailure = true;
|
||||
continue;
|
||||
}
|
||||
mlir::Region* selected = &switchOp.getDefaultRegion();
|
||||
for (auto [caseValue, caseRegion] : llvm::zip(switchOp.getCases(), switchOp.getCaseRegions()))
|
||||
if (caseValue == *selector) {
|
||||
selected = &caseRegion;
|
||||
break;
|
||||
}
|
||||
for (mlir::Region& region : switchOp->getRegions())
|
||||
if (failed(walkPimCoreBlockStructurally(region.front(), knowledge, callback)))
|
||||
hasFailure = true;
|
||||
auto yield = mlir::cast<mlir::scf::YieldOp>(selected->front().getTerminator());
|
||||
for (auto [result, yielded] : llvm::zip(switchOp.getResults(), yield.getOperands()))
|
||||
knowledge.aliases[result] = resolveLoopCarriedAlias(yielded, knowledge);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (failed(callback(op, knowledge)))
|
||||
hasFailure = true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
#include "mlir/Dialect/Linalg/IR/Linalg.h"
|
||||
#include "mlir/Dialect/Tensor/IR/Tensor.h"
|
||||
#include "mlir/Interfaces/SideEffectInterfaces.h"
|
||||
|
||||
#include "ShapingUtils.hpp"
|
||||
#include "src/Accelerators/PIM/Dialect/Spatial/SpatialOps.hpp"
|
||||
#include "src/Dialect/ONNX/ONNXOps.hpp"
|
||||
|
||||
using namespace mlir;
|
||||
|
||||
namespace onnx_mlir {
|
||||
|
||||
bool isShapingOnlyOp(Operation *op) {
|
||||
return isa<tensor::CastOp,
|
||||
tensor::CollapseShapeOp,
|
||||
tensor::ExpandShapeOp,
|
||||
tensor::ExtractSliceOp,
|
||||
tensor::InsertSliceOp,
|
||||
tensor::ConcatOp,
|
||||
tensor::EmptyOp,
|
||||
tensor::ExtractOp,
|
||||
tensor::InsertOp,
|
||||
tensor::SplatOp,
|
||||
linalg::TransposeOp,
|
||||
ONNXTransposeOp,
|
||||
spatial::SpatConcatOp,
|
||||
spatial::SpatExtractRowsOp>(op);
|
||||
}
|
||||
|
||||
bool isPureIndexComputationOp(Operation *op) {
|
||||
if (op->getNumRegions() != 0 || op->getNumResults() == 0 || op->hasTrait<OpTrait::IsTerminator>()
|
||||
|| !isMemoryEffectFree(op))
|
||||
return false;
|
||||
auto isIndexOrInteger = [](Type type) { return type.isIndex() || isa<IntegerType>(type); };
|
||||
return llvm::all_of(op->getOperandTypes(), isIndexOrInteger)
|
||||
&& llvm::all_of(op->getResultTypes(), isIndexOrInteger);
|
||||
}
|
||||
|
||||
} // namespace onnx_mlir
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
namespace mlir {
|
||||
class Operation;
|
||||
}
|
||||
|
||||
namespace onnx_mlir {
|
||||
|
||||
bool isShapingOnlyOp(mlir::Operation *op);
|
||||
|
||||
bool isPureIndexComputationOp(mlir::Operation *op);
|
||||
|
||||
} // namespace onnx_mlir
|
||||
@@ -68,4 +68,39 @@ Value insertStaticSlice(
|
||||
.getResult();
|
||||
}
|
||||
|
||||
FailureOr<Value> addLeadingUnitTensorDimension(OpBuilder& builder, Location loc, Value value) {
|
||||
auto type = dyn_cast<RankedTensorType>(value.getType());
|
||||
if (!type || !type.hasStaticShape())
|
||||
return failure();
|
||||
SmallVector<int64_t> shape {1};
|
||||
llvm::append_range(shape, type.getShape());
|
||||
auto resultType = RankedTensorType::get(shape, type.getElementType(), type.getEncoding());
|
||||
SmallVector<ReassociationIndices> reassociation;
|
||||
if (type.getRank() != 0) {
|
||||
reassociation.push_back({0, 1});
|
||||
for (int64_t dim = 1; dim < type.getRank(); ++dim)
|
||||
reassociation.push_back({dim + 1});
|
||||
}
|
||||
return tensor::ExpandShapeOp::create(builder, loc, resultType, value, reassociation).getResult();
|
||||
}
|
||||
|
||||
FailureOr<Value> removeLeadingUnitTensorDimension(
|
||||
OpBuilder& builder, Location loc, Value value, RankedTensorType resultType) {
|
||||
if (value.getType() == resultType)
|
||||
return value;
|
||||
auto type = dyn_cast<RankedTensorType>(value.getType());
|
||||
if (!type || !resultType || !type.hasStaticShape() || !resultType.hasStaticShape()
|
||||
|| type.getRank() != resultType.getRank() + 1 || type.getDimSize(0) != 1
|
||||
|| type.getElementType() != resultType.getElementType()
|
||||
|| !llvm::equal(type.getShape().drop_front(), resultType.getShape()))
|
||||
return failure();
|
||||
SmallVector<ReassociationIndices> reassociation;
|
||||
if (resultType.getRank() != 0) {
|
||||
reassociation.push_back({0, 1});
|
||||
for (int64_t dim = 1; dim < resultType.getRank(); ++dim)
|
||||
reassociation.push_back({dim + 1});
|
||||
}
|
||||
return tensor::CollapseShapeOp::create(builder, loc, resultType, value, reassociation).getResult();
|
||||
}
|
||||
|
||||
} // namespace onnx_mlir
|
||||
|
||||
@@ -25,4 +25,10 @@ mlir::Value insertStaticSlice(mlir::PatternRewriter& rewriter,
|
||||
mlir::Value dest,
|
||||
llvm::ArrayRef<mlir::OpFoldResult> offsets);
|
||||
|
||||
mlir::FailureOr<mlir::Value>
|
||||
addLeadingUnitTensorDimension(mlir::OpBuilder& builder, mlir::Location loc, mlir::Value value);
|
||||
|
||||
mlir::FailureOr<mlir::Value> removeLeadingUnitTensorDimension(
|
||||
mlir::OpBuilder& builder, mlir::Location loc, mlir::Value value, mlir::RankedTensorType resultType);
|
||||
|
||||
} // namespace onnx_mlir
|
||||
|
||||
Reference in New Issue
Block a user