Cose belle
Validate Operations / validate-operations (push) Has been cancelled

This commit is contained in:
NiccoloN
2026-07-14 16:57:58 +02:00
parent d1a29ace3c
commit 51fdb830e5
38 changed files with 5365 additions and 914 deletions
+1
View File
@@ -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
+29 -29
View File
@@ -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) {
+8 -8
View File
@@ -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,
+13 -7
View File
@@ -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) {
+5 -2
View File
@@ -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);
+47 -2
View File
@@ -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;
}
+39
View File
@@ -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
+13
View File
@@ -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
+35
View File
@@ -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
+6
View File
@@ -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