diff options
| author | Thomas Raoux <thomasraoux@google.com> | 2021-11-10 14:32:15 -0800 |
|---|---|---|
| committer | thomasraoux <thomasraoux@google.com> | 2021-11-11 13:10:38 -0800 |
| commit | e7969240dce5e064f11abd44d7553ba9e9f27210 (patch) | |
| tree | 3bff4301c315d1987449ac8ac3f5378a64668ecd /mlir/lib/Conversion/VectorToGPU/VectorToGPU.cpp | |
| parent | 04cbfa950e0221ac334f802407a9b766df33eee5 (diff) | |
[mlir][VectorToGPU] Support more cases in conversion to MMA ops
Support load with broadcast, elementwise divf op and remove the
hardcoded restriction on the vector size. Picking the right size should
be enfored by user and will fail conversion to llvm/spirv if it is not
supported.
Differential Revision: https://reviews.llvm.org/D113618
Diffstat (limited to 'mlir/lib/Conversion/VectorToGPU/VectorToGPU.cpp')
| -rw-r--r-- | mlir/lib/Conversion/VectorToGPU/VectorToGPU.cpp | 83 |
1 files changed, 59 insertions, 24 deletions
diff --git a/mlir/lib/Conversion/VectorToGPU/VectorToGPU.cpp b/mlir/lib/Conversion/VectorToGPU/VectorToGPU.cpp index a9f3c7da9c84..18f472634480 100644 --- a/mlir/lib/Conversion/VectorToGPU/VectorToGPU.cpp +++ b/mlir/lib/Conversion/VectorToGPU/VectorToGPU.cpp @@ -50,26 +50,7 @@ static bool contractSupportsMMAMatrixType(vector::ContractionOp contract) { if (contract.getIndexingMaps() != infer({{m, k}, {k, n}, {m, n}})) return false; - // Check that the size matches what is natively supported. - VectorType lhsType = contract.lhs().getType().cast<VectorType>(); - VectorType rhsType = contract.rhs().getType().cast<VectorType>(); - VectorType accType = contract.acc().getType().cast<VectorType>(); - - std::tuple<int, int, int> dim(lhsType.getDimSize(0), rhsType.getDimSize(1), - lhsType.getDimSize(1)); - if (lhsType.getElementType().isInteger(8) && - rhsType.getElementType().isInteger(8) && - accType.getElementType().isInteger(32) && - (dim == std::make_tuple(8, 8, 32) || dim == std::make_tuple(16, 16, 32) || - dim == std::make_tuple(16, 8, 32))) - return true; - - if (lhsType.getElementType().isF16() && rhsType.getElementType().isF16() && - (accType.getElementType().isF16() || accType.getElementType().isF32()) && - (dim == std::make_tuple(8, 8, 16) || dim == std::make_tuple(16, 16, 16) || - dim == std::make_tuple(16, 8, 16))) - return true; - return false; + return true; } // Return the stide for the dimension 0 of |type| if it is a memref and has a @@ -95,8 +76,15 @@ static bool transferReadSupportsMMAMatrixType(vector::TransferReadOp readOp) { return false; if (!getMemrefConstantHorizontalStride(readOp.getShapedType())) return false; + AffineMap map = readOp.permutation_map(); + OpBuilder b(readOp.getContext()); + AffineExpr innerDim = b.getAffineDimExpr(map.getNumDims() - 1); + AffineExpr zero = b.getAffineConstantExpr(0); + auto broadcastInnerDim = AffineMap::get(map.getNumDims(), 0, {zero, innerDim}, + readOp.getContext()); // TODO: Support transpose once it is added to GPU dialect ops. - if (!readOp.permutation_map().isMinorIdentity()) + // For now we only support (d0, d1) -> (d0, d1) and (d0, d1) -> (0, d1). + if (!map.isMinorIdentity() && map != broadcastInnerDim) return false; return true; } @@ -142,6 +130,8 @@ convertElementwiseOpToMMA(Operation *op) { return gpu::MMAElementwiseOp::MAXF; if (isa<MinFOp>(op)) return gpu::MMAElementwiseOp::MINF; + if (isa<arith::DivFOp>(op)) + return gpu::MMAElementwiseOp::DIVF; return llvm::None; } @@ -166,6 +156,44 @@ static bool supportsMMaMatrixType(Operation *op) { return elementwiseSupportsMMAMatrixType(op); } +/// Return an unsorted slice handling scf.for region differently than +/// `getSlice`. In scf.for we only want to include as part of the slice elements +/// that are part of the use/def chain. +static SetVector<Operation *> getSliceContract(Operation *op, + TransitiveFilter backwardFilter, + TransitiveFilter forwardFilter) { + SetVector<Operation *> slice; + slice.insert(op); + unsigned currentIndex = 0; + SetVector<Operation *> backwardSlice; + SetVector<Operation *> forwardSlice; + while (currentIndex != slice.size()) { + auto *currentOp = (slice)[currentIndex]; + // Compute and insert the backwardSlice starting from currentOp. + backwardSlice.clear(); + getBackwardSlice(currentOp, &backwardSlice, backwardFilter); + slice.insert(backwardSlice.begin(), backwardSlice.end()); + + // Compute and insert the forwardSlice starting from currentOp. + forwardSlice.clear(); + // Special case for ForOp, we don't want to include the whole region but + // only the value using the region arguments. + // TODO: We should refine this to only care about the region arguments being + // converted to matrix type. + if (auto forOp = dyn_cast<scf::ForOp>(currentOp)) { + for (Value forOpResult : forOp.getResults()) + getForwardSlice(forOpResult, &forwardSlice, forwardFilter); + for (BlockArgument &arg : forOp.getRegionIterArgs()) + getForwardSlice(arg, &forwardSlice, forwardFilter); + } else { + getForwardSlice(currentOp, &forwardSlice, forwardFilter); + } + slice.insert(forwardSlice.begin(), forwardSlice.end()); + ++currentIndex; + } + return slice; +} + // Analyze slice of operations based on convert op to figure out if the whole // slice can be converted to MMA operations. static SetVector<Operation *> getOpToConvert(mlir::Operation *op) { @@ -182,16 +210,17 @@ static SetVector<Operation *> getOpToConvert(mlir::Operation *op) { if (opToConvert.contains(contract.getOperation())) return; SetVector<Operation *> dependentOps = - getSlice(contract, hasVectorDest, hasVectorSrc); + getSliceContract(contract, hasVectorDest, hasVectorSrc); // If any instruction cannot use MMA matrix type drop the whole - // chaine. MMA matrix are stored in an opaque type so they cannot be used + // chain. MMA matrix are stored in an opaque type so they cannot be used // by all operations. if (llvm::any_of(dependentOps, [](Operation *op) { return !supportsMMaMatrixType(op); })) return; opToConvert.insert(dependentOps.begin(), dependentOps.end()); }); - return opToConvert; + // Sort the operations so that we can convert them in topological order. + return topologicalSort(opToConvert); } namespace { @@ -309,6 +338,12 @@ static void convertTransferReadOp(vector::TransferReadOp op, assert(transferReadSupportsMMAMatrixType(op)); Optional<int64_t> stride = getMemrefConstantHorizontalStride(op.getShapedType()); + AffineMap map = op.permutation_map(); + // Handle broadcast by setting the stride to 0. + if (map.getResult(0).isa<AffineConstantExpr>()) { + assert(map.getResult(0).cast<AffineConstantExpr>().getValue() == 0); + stride = 0; + } assert(stride); const char *fragType = inferFragType(op); gpu::MMAMatrixType type = |
