28#define GEN_PASS_DEF_ARITHTOAMDGPUCONVERSIONPASS
29#include "mlir/Conversion/Passes.h.inc"
40struct ArithToAMDGPUConversionPass final
42 using impl::ArithToAMDGPUConversionPassBase<
43 ArithToAMDGPUConversionPass>::ArithToAMDGPUConversionPassBase;
45 void runOnOperation()
override;
52 ExtFOnFloat8RewritePattern(MLIRContext *ctx, Chipset chipset,
53 PatternBenefit benefit)
54 : OpRewritePattern::OpRewritePattern(ctx, benefit), chipset(chipset) {}
56 LogicalResult matchAndRewrite(arith::ExtFOp op,
57 PatternRewriter &rewriter)
const override;
60struct TruncFToFloat8RewritePattern final :
OpRewritePattern<arith::TruncFOp> {
61 bool saturateFP8 =
false;
62 TruncFToFloat8RewritePattern(MLIRContext *ctx,
bool saturateFP8,
63 Chipset chipset, PatternBenefit benefit)
64 : OpRewritePattern::OpRewritePattern(ctx, benefit),
65 saturateFP8(saturateFP8), chipset(chipset) {}
68 LogicalResult matchAndRewrite(arith::TruncFOp op,
69 PatternRewriter &rewriter)
const override;
72struct TruncfToFloat16RewritePattern final
77 LogicalResult matchAndRewrite(arith::TruncFOp op,
78 PatternRewriter &rewriter)
const override;
81struct ScalingExtFRewritePattern final
85 LogicalResult matchAndRewrite(arith::ScalingExtFOp op,
86 PatternRewriter &rewriter)
const override;
89struct ScalingTruncFRewritePattern final
93 LogicalResult matchAndRewrite(arith::ScalingTruncFOp op,
94 PatternRewriter &rewriter)
const override;
101 return isa<Float8E4M3FNUZType, Float8E5M2FNUZType>(elementType);
103 return isa<Float8E4M3FNType, Float8E5M2Type>(elementType);
110 if (elementType.
isF32())
113 return arith::TruncFOp::create(rewriter, loc, desType, f32);
115 return arith::ExtFOp::create(rewriter, loc, desType, f32);
116 llvm_unreachable(
"The only 32-bit float type is f32");
120ExtFOnFloat8RewritePattern::matchAndRewrite(arith::ExtFOp op,
122 Type inType = op.getIn().getType();
123 auto inVecType = dyn_cast<VectorType>(inType);
125 if (inVecType.isScalable())
127 inType = inVecType.getElementType();
135 VectorType extResType = VectorType::get(2, rewriter.
getF32Type());
137 Value asFloat = amdgpu::ExtPackedFp8Op::create(
143 int64_t numElements = inVecType.getNumElements();
145 Value zero = arith::ConstantOp::create(
146 rewriter, loc, outElemType, rewriter.
getFloatAttr(outElemType, 0.0));
147 VectorType outType = cast<VectorType>(op.getOut().getType());
149 if (inVecType.getShape().empty()) {
151 rewriter.
createOrFold<vector::BroadcastOp>(loc, outType, zero);
155 arith::ExtFOp::create(rewriter, loc, outElemType, scalarIn);
156 Value result = vector::InsertOp::create(rewriter, loc, scalarExt,
163 outType.getElementType());
166 if (inVecType.getRank() > 1) {
168 inVecType.getElementType());
169 in = vector::ShapeCastOp::create(rewriter, loc, inVecType, in);
172 for (
int64_t i = 0; i < numElements; i += 4) {
173 int64_t elemsThisOp = std::min(numElements, i + 4) - i;
174 Value inSlice = vector::ExtractStridedSliceOp::create(rewriter, loc, in, i,
176 for (
int64_t j = 0;
j < elemsThisOp;
j += 2) {
177 if (i +
j + 1 < numElements) {
178 Value asFloats = amdgpu::ExtPackedFp8Op::create(
179 rewriter, loc, extResType, inSlice,
j / 2);
180 Type desType = VectorType::get(2, outElemType);
182 result = vector::InsertStridedSliceOp::create(rewriter, loc, asType,
185 Value asFloat = amdgpu::ExtPackedFp8Op::create(
186 rewriter, loc, rewriter.
getF32Type(), inSlice,
j / 2 * 2);
193 if (inVecType.getRank() != outType.getRank()) {
194 result = vector::ShapeCastOp::create(rewriter, loc, outType,
result);
206 return arith::ExtFOp::create(rewriter, loc, rewriter.
getF32Type(), value);
208 return arith::TruncFOp::create(rewriter, loc, rewriter.
getF32Type(), value);
209 llvm_unreachable(
"The only 32-bit float type is f32");
220 const llvm::fltSemantics &sourceSem =
222 const llvm::fltSemantics &targetSem =
223 cast<FloatType>(outElemType).getFloatSemantics();
225 APFloat
min = APFloat::getLargest(targetSem,
true);
226 APFloat
max = APFloat::getLargest(targetSem,
false);
227 bool ignoredLosesInfo =
false;
231 (
void)
min.convert(sourceSem, APFloat::rmNearestTiesToEven, &ignoredLosesInfo);
232 (
void)
max.convert(sourceSem, APFloat::rmNearestTiesToEven, &ignoredLosesInfo);
238 rewriter, loc, sourceType,
239 APFloat::getInf(sourceSem,
false));
241 rewriter, loc, sourceType, APFloat::getInf(sourceSem,
true));
243 loc, arith::CmpFPredicate::OEQ, source, inf);
245 loc, arith::CmpFPredicate::OEQ, source, negInf);
247 loc, arith::CmpFPredicate::UNO, source, source);
248 Value isNonFinite = arith::OrIOp::create(
249 rewriter, loc, arith::OrIOp::create(rewriter, loc, isInf, isNegInf),
252 Value clampedBelow = arith::MaximumFOp::create(rewriter, loc, source, minCst);
254 arith::MinimumFOp::create(rewriter, loc, clampedBelow, maxCst);
256 arith::SelectOp::create(rewriter, loc, isNonFinite, source, clamped);
261TruncFToFloat8RewritePattern::matchAndRewrite(arith::TruncFOp op,
262 PatternRewriter &rewriter)
const {
264 if (op.getRoundingmodeAttr())
266 Type outType = op.getOut().getType();
267 auto outVecType = dyn_cast<VectorType>(outType);
269 if (outVecType.isScalable())
271 outType = outVecType.getElementType();
274 if (inType && inType.getWidth() <= 8 && saturateFP8)
281 Location loc = op.getLoc();
282 Value in = op.getIn();
285 in =
clampInput(rewriter, loc, outElemType, in);
286 auto inVectorTy = dyn_cast<VectorType>(in.
getType());
287 VectorType truncResType = VectorType::get(4, outElemType);
289 Value asFloat =
castToF32(in, loc, rewriter);
290 Value asF8s = amdgpu::PackedTrunc2xFp8Op::create(
291 rewriter, loc, truncResType, asFloat,
nullptr, 0,
293 Value
result = vector::ExtractOp::create(rewriter, loc, asF8s, 0);
298 int64_t numElements = outVecType.getNumElements();
299 Value zero = arith::ConstantOp::create(
300 rewriter, loc, outElemType, rewriter.
getFloatAttr(outElemType, 0.0));
301 if (outVecType.getShape().empty()) {
303 vector::ExtractOp::create(rewriter, loc, in, ArrayRef<int64_t>{});
306 arith::TruncFOp::create(rewriter, loc, outElemType, scalarIn);
307 Value
result = vector::InsertOp::create(rewriter, loc, scalarTrunc, zero,
308 ArrayRef<int64_t>{});
313 VectorType flatTy = VectorType::get(SmallVector<int64_t>{numElements},
314 outVecType.getElementType());
317 if (inVectorTy.getRank() > 1) {
318 inVectorTy = VectorType::get(SmallVector<int64_t>{numElements},
319 inVectorTy.getElementType());
320 in = vector::ShapeCastOp::create(rewriter, loc, inVectorTy, in);
323 for (int64_t i = 0; i < numElements; i += 4) {
324 int64_t elemsThisOp = std::min(numElements, i + 4) - i;
325 Value thisResult =
nullptr;
326 for (int64_t j = 0; j < elemsThisOp; j += 2) {
327 Value elemA = vector::ExtractOp::create(rewriter, loc, in, i + j);
328 Value asFloatA =
castToF32(elemA, loc, rewriter);
329 Value asFloatB =
nullptr;
330 if (j + 1 < elemsThisOp) {
331 Value elemB = vector::ExtractOp::create(rewriter, loc, in, i + j + 1);
332 asFloatB =
castToF32(elemB, loc, rewriter);
334 thisResult = amdgpu::PackedTrunc2xFp8Op::create(
335 rewriter, loc, truncResType, asFloatA, asFloatB, j / 2, thisResult);
338 thisResult = vector::ExtractStridedSliceOp::create(
339 rewriter, loc, thisResult, 0, elemsThisOp, 1);
340 result = vector::InsertStridedSliceOp::create(rewriter, loc, thisResult,
344 if (inVectorTy.getRank() != outVecType.getRank()) {
345 result = vector::ShapeCastOp::create(rewriter, loc, outVecType,
result);
352LogicalResult TruncfToFloat16RewritePattern::matchAndRewrite(
353 arith::TruncFOp op, PatternRewriter &rewriter)
const {
354 Type outType = op.getOut().getType();
356 auto outVecType = dyn_cast<VectorType>(outType);
358 if (outVecType.isScalable())
360 outType = outVecType.getElementType();
365 Location loc = op.getLoc();
366 Value in = op.getIn();
368 VectorType truncResType = VectorType::get(2, outElemType);
369 auto inVectorTy = dyn_cast<VectorType>(in.
getType());
373 auto sourceB = LLVM::PoisonOp::create(rewriter, loc, rewriter.
getF32Type());
375 ROCDL::CvtPkRtz::create(rewriter, loc, truncResType, in, sourceB);
376 Value
result = vector::ExtractOp::create(rewriter, loc, asF16s, 0);
380 int64_t numElements = outVecType.getNumElements();
382 loc, outElemType, rewriter.
getFloatAttr(outElemType, 0.0));
384 rewriter.
createOrFold<vector::BroadcastOp>(loc, outVecType, zero);
386 if (inVectorTy.getRank() > 1) {
387 inVectorTy = VectorType::get(SmallVector<int64_t>{numElements},
388 inVectorTy.getElementType());
389 in = vector::ShapeCastOp::create(rewriter, loc, inVectorTy, in);
394 for (int64_t i = 0; i < numElements; i += 2) {
395 int64_t elemsThisOp = std::min(numElements, i + 2) - i;
396 Value thisResult =
nullptr;
397 Value elemA = vector::ExtractOp::create(rewriter, loc, in, i);
398 Value elemB = LLVM::PoisonOp::create(rewriter, loc, rewriter.
getF32Type());
400 if (elemsThisOp == 2) {
401 elemB = vector::ExtractOp::create(rewriter, loc, in, i + 1);
405 ROCDL::CvtPkRtz::create(rewriter, loc, truncResType, elemA, elemB);
408 thisResult = vector::ExtractStridedSliceOp::create(
409 rewriter, loc, thisResult, 0, elemsThisOp, 1);
410 result = vector::InsertStridedSliceOp::create(rewriter, loc, thisResult,
414 if (inVectorTy.getRank() != outVecType.getRank()) {
415 result = vector::ShapeCastOp::create(rewriter, loc, outVecType,
result);
424 Value current = value;
427 .Case([¤t](vector::ShapeCastOp op) {
428 current = op.getSource();
431 .Case([¤t](vector::BroadcastOp op) {
432 current = op.getSource();
445ScalingExtFRewritePattern::matchAndRewrite(arith::ScalingExtFOp op,
446 PatternRewriter &rewriter)
const {
447 Location loc = op.getLoc();
448 constexpr int64_t opOutWidth = 2;
450 Value in = op.getIn();
451 Value scale = op.getScale();
452 Value out = op.getOut();
461 VectorType outVecType = dyn_cast<VectorType>(out.
getType());
462 VectorType scaleVecType = dyn_cast<VectorType>(scale.
getType());
464 if (outVecType && outVecType.isScalable())
467 if (isa<RankedTensorType>(out.
getType()) ||
468 isa<RankedTensorType>(in.
getType()) ||
469 isa<RankedTensorType>(scale.
getType()))
473 scaleVecType ? VectorType::get(scaleVecType.getShape(), f32) : f32;
475 scale = arith::ExtFOp::create(rewriter, loc, scaleF32Type, scale);
477 scale = arith::TruncFOp::create(rewriter, loc, scaleF32Type, scale);
479 VectorType extScaleResultType = VectorType::get(opOutWidth, outType);
482 Value inCast = vector::BroadcastOp::create(rewriter, loc,
483 VectorType::get(1, inType), in);
485 Value scaleExt = amdgpu::ScaledExtPackedOp::create(
486 rewriter, loc, extScaleResultType, inCast, scale, 0);
491 VectorType inVecType = cast<VectorType>(in.
getType());
493 VectorType origScaleVecType = dyn_cast<VectorType>(origScale.
getType());
495 ArrayRef<int64_t> inShape = inVecType.getShape();
496 SmallVector<int64_t> originalScaleShape;
497 if (origScaleVecType)
498 llvm::append_range(originalScaleShape, origScaleVecType.getShape());
500 originalScaleShape.insert(originalScaleShape.end(),
501 inShape.size() - originalScaleShape.size(), 1);
505 "failed to derive block size from broadcast or splat operation");
507 SmallVector<int64_t> ratio =
508 maybeRatio.value_or(SmallVector<int64_t>(inShape.size(), 1));
512 Value zero = arith::ConstantOp::create(rewriter, loc, outType,
515 rewriter.
createOrFold<vector::BroadcastOp>(loc, outVecType, zero);
517 for (SmallVector<int64_t> offsets : StaticTileOffsetRange(inShape, ratio)) {
518 SmallVector<int64_t> strides(offsets.size(), 1);
519 Value block = vector::ExtractStridedSliceOp::create(
520 rewriter, loc, in, offsets, ratio, strides);
521 VectorType block1DType = VectorType::get(blockSize, inType);
523 vector::ShapeCastOp::create(rewriter, loc, block1DType, block);
525 vector::ExtractOp::create(rewriter, loc, scale, offsets);
527 VectorType blockResultType = VectorType::get(blockSize, outType);
529 rewriter.
createOrFold<vector::BroadcastOp>(loc, blockResultType, zero);
531 for (int64_t i = 0, inSliceWidth = std::min(opInWidth, blockSize - i);
533 i += inSliceWidth, inSliceWidth = std::min(opInWidth, blockSize - i)) {
534 Value inSlice = vector::ExtractStridedSliceOp::create(
535 rewriter, loc, block1D, i, inSliceWidth, 1);
537 outSliceWidth = std::min(opOutWidth, inSliceWidth - j);
538 j < inSliceWidth; j += outSliceWidth,
539 outSliceWidth = std::min(opOutWidth, inSliceWidth - j)) {
541 Value scaleExt = amdgpu::ScaledExtPackedOp::create(
542 rewriter, loc, extScaleResultType, inSlice, uniformScale,
544 if (outSliceWidth < opOutWidth) {
545 scaleExt = vector::ExtractStridedSliceOp::create(
546 rewriter, loc, scaleExt, 0, outSliceWidth, 1);
548 blockResult = vector::InsertStridedSliceOp::create(
549 rewriter, loc, scaleExt, blockResult, i + j, 1);
553 VectorType resultType = VectorType::get(ratio, outType);
555 vector::ShapeCastOp::create(rewriter, loc, resultType, blockResult);
556 result = vector::InsertStridedSliceOp::create(rewriter, loc, cast,
result,
566ScalingTruncFRewritePattern::matchAndRewrite(arith::ScalingTruncFOp op,
567 PatternRewriter &rewriter)
const {
568 Location loc = op.getLoc();
569 constexpr int64_t opInWidth = 2;
571 Value in = op.getIn();
572 Value scale = op.getScale();
573 Value out = op.getOut();
580 VectorType outVecType = dyn_cast<VectorType>(out.
getType());
581 VectorType scaleVecType = dyn_cast<VectorType>(scale.
getType());
582 if (outVecType && outVecType.isScalable())
585 if (isa<RankedTensorType>(out.
getType()) ||
586 isa<RankedTensorType>(in.
getType()) ||
587 isa<RankedTensorType>(scale.
getType()))
591 scaleVecType ? VectorType::get(scaleVecType.getShape(), f32) : f32;
593 scale = arith::ExtFOp::create(rewriter, loc, scaleF32Type, scale);
595 scale = arith::TruncFOp::create(rewriter, loc, scaleF32Type, scale);
597 Value zero = arith::ConstantOp::create(rewriter, loc, outType,
600 VectorType truncScaleResultType = VectorType::get(opOutWidth, outType);
603 Type inVecType = VectorType::get(1, inType);
604 Value inCast = vector::BroadcastOp::create(rewriter, loc, inVecType, in);
606 Value scaleTrunc = amdgpu::PackedScaledTruncOp::create(
607 rewriter, loc, truncScaleResultType, inCast, scale, 0,
614 VectorType inVecType = cast<VectorType>(in.
getType());
616 VectorType origScaleVecType = dyn_cast<VectorType>(origScale.
getType());
618 ArrayRef<int64_t> inShape = inVecType.getShape();
619 SmallVector<int64_t> scaleShape;
620 if (origScaleVecType)
621 llvm::append_range(scaleShape, origScaleVecType.getShape());
623 scaleShape.insert(scaleShape.end(), inShape.size() - scaleShape.size(), 1);
627 "failed to derive block size from broadcast or splat operation");
629 SmallVector<int64_t> ratio =
630 maybeRatio.value_or(SmallVector<int64_t>(inShape.size(), 1));
635 rewriter.
createOrFold<vector::BroadcastOp>(loc, outVecType, zero);
637 for (SmallVector<int64_t> offsets : StaticTileOffsetRange(inShape, ratio)) {
638 SmallVector<int64_t> strides(offsets.size(), 1);
639 Value block = vector::ExtractStridedSliceOp::create(
640 rewriter, loc, in, offsets, ratio, strides);
641 VectorType block1DType = VectorType::get(blockSize, inType);
643 vector::ShapeCastOp::create(rewriter, loc, block1DType, block);
645 vector::ExtractOp::create(rewriter, loc, scale, offsets);
647 VectorType blockResultType = VectorType::get(blockSize, outType);
649 rewriter.
createOrFold<vector::BroadcastOp>(loc, blockResultType, zero);
651 for (int64_t i = 0, outSliceWidth = std::min(opOutWidth, blockSize - i);
652 i < blockSize; i += outSliceWidth,
653 outSliceWidth = std::min(opOutWidth, blockSize - i)) {
656 if (outSliceWidth <= opInWidth) {
657 Value slice = vector::ExtractStridedSliceOp::create(
658 rewriter, loc, block1D, i, outSliceWidth, 1);
660 scaleTrunc = amdgpu::PackedScaledTruncOp::create(
661 rewriter, loc, truncScaleResultType, slice, uniformScale, 0,
664 scaleTrunc = vector::BroadcastOp::create(rewriter, loc,
665 truncScaleResultType, zero);
667 inSliceWidth = std::min(opInWidth, outSliceWidth - j);
668 j < outSliceWidth; j += opInWidth,
669 inSliceWidth = std::min(opInWidth, outSliceWidth - j)) {
670 Value slice = vector::ExtractStridedSliceOp::create(
671 rewriter, loc, block1D, i + j, inSliceWidth, 1);
672 scaleTrunc = amdgpu::PackedScaledTruncOp::create(
673 rewriter, loc, truncScaleResultType, slice, uniformScale,
674 j / opInWidth, scaleTrunc);
677 if (outSliceWidth != opOutWidth) {
678 scaleTrunc = vector::ExtractStridedSliceOp::create(
679 rewriter, loc, scaleTrunc, 0, outSliceWidth, 1);
681 blockResult = vector::InsertStridedSliceOp::create(
682 rewriter, loc, scaleTrunc, blockResult, i, 1);
685 VectorType resultType = VectorType::get(ratio, outType);
687 vector::ShapeCastOp::create(rewriter, loc, resultType, blockResult);
688 result = vector::InsertStridedSliceOp::create(rewriter, loc, cast,
result,
699 bool saturateFP8Truncf,
bool allowPackedF16Rtz,
bool supportsScaledExtTrunc,
702 if (convertFP8Arithmetic) {
703 patterns.
add<ExtFOnFloat8RewritePattern>(patterns.
getContext(), chipset,
705 patterns.
add<TruncFToFloat8RewritePattern>(
706 patterns.
getContext(), saturateFP8Truncf, chipset, benefit);
708 if (allowPackedF16Rtz)
709 patterns.
add<TruncfToFloat16RewritePattern>(patterns.
getContext(), benefit);
711 if (supportsScaledExtTrunc) {
712 patterns.
add<ScalingExtFRewritePattern>(patterns.
getContext(), benefit);
713 patterns.
add<ScalingTruncFRewritePattern>(patterns.
getContext(), benefit);
717void ArithToAMDGPUConversionPass::runOnOperation() {
722 if (failed(maybeChipset)) {
723 emitError(UnknownLoc::get(ctx),
"Invalid chipset name: " + chipset);
724 return signalPassFailure();
727 bool convertFP8Arithmetic =
729 bool supportsScaledExtTrunc = *maybeChipset ==
kGfx950;
731 patterns, convertFP8Arithmetic, saturateFP8Truncf, allowPackedF16Rtz,
732 supportsScaledExtTrunc, *maybeChipset);
734 return signalPassFailure();
constexpr Chipset kGfx942
constexpr Chipset kGfx950
static Value getOriginalVectorValue(Value value)
Get the broadcasted / splatted value for a chain of ops.
static Value castF32To(Type desType, Value f32, Location loc, PatternRewriter &rewriter)
static Value castToF32(Value value, Location loc, PatternRewriter &rewriter)
static bool isSupportedF8(Type elementType, Chipset chipset)
static Value clampInput(PatternRewriter &rewriter, Location loc, Type outElemType, Value source)
static Value max(ImplicitLocOpBuilder &builder, Value value, Value bound)
static Value min(ImplicitLocOpBuilder &builder, Value value, Value bound)
FloatAttr getFloatAttr(Type type, double value)
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
MLIRContext is the top-level object for a collection of MLIR operations.
void createOrFold(SmallVectorImpl< Value > &results, Location location, Args &&...args)
Create an operation of specific op type at the current insertion point, and immediately try to fold i...
Operation is the basic unit of execution within MLIR.
MLIRContext * getContext()
Return the context this operation is associated with.
This class represents the benefit of a pattern match in a unitless scheme that ranges from 0 (very li...
A special type of RewriterBase that coordinates the application of a rewrite pattern on the current I...
MLIRContext * getContext() const
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
virtual void replaceOp(Operation *op, ValueRange newValues)
Replace the results of the given (original) operation with the specified list of values (replacements...
OpTy replaceOpWithNewOp(Operation *op, Args &&...args)
Replace the results of the given (original) op with a new op that is created without verification (re...
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
::mlir::Pass::Option< std::string > chipset
bool hasOcpFp8(const Chipset &chipset)
void populateArithToAMDGPUConversionPatterns(RewritePatternSet &patterns, bool convertFP8Arithmetic, bool saturateFP8Truncf, bool allowPackedF16Rtz, bool supportsScaledExtTrunc, amdgpu::Chipset chipset, PatternBenefit benefit=1)
Add patterns for rewriting arith.extf and arith.truncf on FP8 types to wrappers around AMDGPU–specifi...
Include the generated interface declarations.
Value createScalarOrSplatConstant(OpBuilder &builder, Location loc, Type type, const APInt &value)
Create a constant of type type at location loc whose value is value (an APInt or APFloat whose type m...
LogicalResult applyPatternsGreedily(Region ®ion, const FrozenRewritePatternSet &patterns, GreedyRewriteConfig config=GreedyRewriteConfig(), bool *changed=nullptr)
Rewrite ops in the given region, which must be isolated from above, by repeatedly applying the highes...
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
int64_t computeProduct(ArrayRef< int64_t > basis)
Self-explicit.
Type getElementTypeOrSelf(Type type)
Return the element type or return the type itself.
std::optional< SmallVector< int64_t > > computeShapeRatio(ArrayRef< int64_t > shape, ArrayRef< int64_t > subShape)
Return the multi-dimensional integral ratio of subShape to the trailing dimensions of shape.
OpRewritePattern is a wrapper around RewritePattern that allows for matching and rewriting against an...
Represents the amdgpu gfx chipset version, e.g., gfx90a, gfx942, gfx1103.
static FailureOr< Chipset > parse(StringRef name)
Parses the chipset version string and returns the chipset on success, and failure otherwise.
Eliminates variable at the specified position using Fourier-Motzkin variable elimination.