MLIR 24.0.0git
LegalizeForLLVMExport.cpp
Go to the documentation of this file.
1//===- LegalizeForLLVMExport.cpp - Prepare ArmSVE for LLVM translation ----===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
18
19using namespace mlir;
20using namespace mlir::arm_sve;
21
31 OneToOneConvertToLLVMPattern<ScalableMaskedAddIOp,
32 ScalableMaskedAddIIntrOp>;
34 OneToOneConvertToLLVMPattern<ScalableMaskedAddFOp,
35 ScalableMaskedAddFIntrOp>;
37 OneToOneConvertToLLVMPattern<ScalableMaskedSubIOp,
38 ScalableMaskedSubIIntrOp>;
40 OneToOneConvertToLLVMPattern<ScalableMaskedSubFOp,
41 ScalableMaskedSubFIntrOp>;
43 OneToOneConvertToLLVMPattern<ScalableMaskedMulIOp,
44 ScalableMaskedMulIIntrOp>;
46 OneToOneConvertToLLVMPattern<ScalableMaskedMulFOp,
47 ScalableMaskedMulFIntrOp>;
49 OneToOneConvertToLLVMPattern<ScalableMaskedSDivIOp,
50 ScalableMaskedSDivIIntrOp>;
52 OneToOneConvertToLLVMPattern<ScalableMaskedUDivIOp,
53 ScalableMaskedUDivIIntrOp>;
55 OneToOneConvertToLLVMPattern<ScalableMaskedDivFOp,
56 ScalableMaskedDivFIntrOp>;
57
58namespace {
59
60/// Unrolls a conversion to/from equivalent vector types, to allow using a
61/// conversion intrinsic that only supports 1-D vector types.
62///
63/// Example:
64/// ```
65/// %result = arm_sve.convert_to_svbool %source : vector<2x[4]xi1>
66/// ```
67/// is rewritten into:
68/// ```
69/// %cst = arith.constant dense<false> : vector<2x[16]xi1>
70/// %1 = vector.extract %source[0] : vector<[4]xi1> from vector<2x[4]xi1>
71/// %2 = "arm_sve.intr.convert.to.svbool"(%1)
72/// : (vector<[4]xi1>) -> vector<[16]xi1>
73/// %3 = vector.insert %2, %cst[0] : vector<[16]xi1> into vector<2x[16]xi1>
74/// %4 = vector.extract %source[1] : vector<[4]xi1> from vector<2x[4]xi1>
75/// %5 = "arm_sve.intr.convert.to.svbool"(%4)
76/// : (vector<[4]xi1>) -> vector<[16]xi1>
77/// %result = vector.insert %5, %3[1] : vector<[16]xi1> into vector<2x[16]xi1>
78/// ```
79template <typename Op, typename IntrOp>
80struct SvboolConversionOpLowering : public ConvertOpToLLVMPattern<Op> {
82
83 LogicalResult
84 matchAndRewrite(Op convertOp, typename Op::Adaptor,
85 ConversionPatternRewriter &rewriter) const override {
86 auto loc = convertOp.getLoc();
87
88 auto source = convertOp.getSource();
89 VectorType sourceType = source.getType();
90 VectorType resultType = convertOp.getResult().getType();
91
92 Value result = arith::ConstantOp::create(rewriter, loc, resultType,
93 rewriter.getZeroAttr(resultType));
94
95 // We want to iterate over the input vector in steps of the trailing
96 // dimension. So this creates tile shape where all leading dimensions are 1,
97 // and the trailing dimension step is the size of the dimension.
98 SmallVector<int64_t> tileShape(sourceType.getRank(), 1);
99 tileShape.back() = sourceType.getShape().back();
100
101 // Iterate over all scalable mask/predicate slices of the source vector.
103 StaticTileOffsetRange(sourceType.getShape(), tileShape)) {
104 auto extractOrInsertPosition = ArrayRef(index).drop_back();
105 auto sourceVector = vector::ExtractOp::create(rewriter, loc, source,
106 extractOrInsertPosition);
107 VectorType convertedType =
108 VectorType::Builder(llvm::cast<VectorType>(sourceVector.getType()))
109 .setDim(0, resultType.getShape().back());
110 auto convertedVector =
111 IntrOp::create(rewriter, loc, TypeRange{convertedType}, sourceVector);
112 result = vector::InsertOp::create(rewriter, loc, convertedVector, result,
113 extractOrInsertPosition);
114 }
115
116 rewriter.replaceOp(convertOp, result);
117 return success();
118 }
119};
120
121using ConvertToSvboolOpLowering =
122 SvboolConversionOpLowering<ConvertToSvboolOp, ConvertToSvboolIntrOp>;
123
124using ConvertFromSvboolOpLowering =
125 SvboolConversionOpLowering<ConvertFromSvboolOp, ConvertFromSvboolIntrOp>;
126
129
130/// Lower `arm_sve.psel` to LLVM intrinsics. This is almost a 1-to-1 conversion
131/// but first input (P1) and result predicates need conversion to/from svbool.
132struct PselOpLowering : public ConvertOpToLLVMPattern<PselOp> {
134
135 LogicalResult
136 matchAndRewrite(PselOp pselOp, PselOp::Adaptor adaptor,
137 ConversionPatternRewriter &rewriter) const override {
138 auto svboolType = VectorType::get(16, rewriter.getI1Type(), true);
139 auto loc = pselOp.getLoc();
140 auto svboolP1 = ConvertToSvboolIntrOp::create(rewriter, loc, svboolType,
141 adaptor.getP1());
142 auto indexI32 = arith::IndexCastOp::create(
143 rewriter, loc, rewriter.getI32Type(), pselOp.getIndex());
144 auto pselIntr = PselIntrOp::create(rewriter, loc, svboolType, svboolP1,
145 pselOp.getP2(), indexI32);
146 rewriter.replaceOpWithNewOp<ConvertFromSvboolIntrOp>(
147 pselOp, adaptor.getP1().getType(), pselIntr);
148 return success();
149 }
150};
151
152/// Converts `vector.create_mask` ops that match the size of an SVE predicate
153/// to the `whilelt` intrinsic. This produces more canonical codegen than the
154/// generic LLVM lowering, see https://github.com/llvm/llvm-project/issues/81840
155/// for more details. Note that we can't use (the more general) active.lane.mask
156/// as its semantics don't neatly map on to `vector.create_mask`, as it does an
157/// unsigned comparison (whereas `create_mask` is signed), and is UB/posion if
158/// `n` is zero (whereas `create_mask` just returns an all-false mask).
159struct CreateMaskOpLowering
160 : public ConvertOpToLLVMPattern<vector::CreateMaskOp> {
162
163 LogicalResult
164 matchAndRewrite(vector::CreateMaskOp createMaskOp,
165 vector::CreateMaskOp::Adaptor adaptor,
166 ConversionPatternRewriter &rewriter) const override {
167 auto maskType = createMaskOp.getVectorType();
168 if (maskType.getRank() != 1 || !maskType.isScalable())
169 return rewriter.notifyMatchFailure(createMaskOp, "not 1-D and scalable");
170
171 // TODO: Support masks which are multiples of SVE predicates.
172 auto maskBaseSize = maskType.getDimSize(0);
173 if (maskBaseSize < 2 || maskBaseSize > 16 ||
174 !llvm::isPowerOf2_32(uint32_t(maskBaseSize)))
175 return rewriter.notifyMatchFailure(createMaskOp,
176 "not SVE predicate-sized");
177
178 auto loc = createMaskOp.getLoc();
179 auto zero = LLVM::ZeroOp::create(rewriter, loc, rewriter.getI64Type());
180 rewriter.replaceOpWithNewOp<WhileLTIntrOp>(createMaskOp, maskType, zero,
181 adaptor.getOperands()[0]);
182 return success();
183 }
184};
185
186} // namespace
187
188/// Populate the given list with patterns that convert from ArmSVE to LLVM.
190 const LLVMTypeConverter &converter, RewritePatternSet &patterns) {
191 // Populate conversion patterns
192
193 // clang-format off
194 patterns.add<ConvertFromSvboolOpLowering,
195 ConvertToSvboolOpLowering,
197 PselOpLowering,
212 ZipX2OpLowering,
213 ZipX4OpLowering,
214 SdotOpLowering>(converter);
215 // Add vector.create_mask conversion with a high benefit as it produces much
216 // nicer code than the generic lowering.
217 patterns.add<CreateMaskOpLowering>(converter, /*benefit=*/4096);
218 // clang-format on
219}
220
223 // clang-format off
224 target.addLegalOp<BfmmlaOp,
225 ConvertFromSvboolIntrOp,
226 ConvertToSvboolIntrOp,
227 DupQLaneIntrOp,
228 PselIntrOp,
229 ScalableMaskedAddFIntrOp,
230 ScalableMaskedAddIIntrOp,
231 ScalableMaskedDivFIntrOp,
232 ScalableMaskedMulFIntrOp,
233 ScalableMaskedMulIIntrOp,
234 ScalableMaskedSDivIIntrOp,
235 ScalableMaskedSubFIntrOp,
236 ScalableMaskedSubIIntrOp,
237 ScalableMaskedUDivIIntrOp,
238 SmmlaIntrOp,
239 UdotIntrOp,
240 FmlaIntrOp,
241 UmmlaIntrOp,
242 UsmmlaIntrOp,
243 WhileLTIntrOp,
244 ZipX2IntrOp,
245 ZipX4IntrOp,
246 SdotIntrOp>();
247 target.addIllegalOp<ConvertFromSvboolOp,
248 ConvertToSvboolOp,
249 DupQLaneOp,
250 PselOp,
251 ScalableMaskedAddFOp,
252 ScalableMaskedAddIOp,
253 ScalableMaskedDivFOp,
254 ScalableMaskedMulFOp,
255 ScalableMaskedMulIOp,
256 ScalableMaskedSDivIOp,
257 ScalableMaskedSubFOp,
258 ScalableMaskedSubIOp,
259 ScalableMaskedUDivIOp,
260 SmmlaOp,
261 UdotOp,
262 FmlaOp,
263 UmmlaOp,
264 UsmmlaOp,
265 ZipX2Op,
266 ZipX4Op,
267 SdotOp>();
268 // clang-format on
269}
return success()
OneToOneConvertToLLVMPattern< ScalableMaskedMulIOp, ScalableMaskedMulIIntrOp > ScalableMaskedMulIOpLowering
OneToOneConvertToLLVMPattern< ScalableMaskedAddFOp, ScalableMaskedAddFIntrOp > ScalableMaskedAddFOpLowering
OneToOneConvertToLLVMPattern< UmmlaOp, UmmlaIntrOp > UmmlaOpLowering
OneToOneConvertToLLVMPattern< ScalableMaskedMulFOp, ScalableMaskedMulFIntrOp > ScalableMaskedMulFOpLowering
OneToOneConvertToLLVMPattern< SdotOp, SdotIntrOp > SdotOpLowering
OneToOneConvertToLLVMPattern< ScalableMaskedUDivIOp, ScalableMaskedUDivIIntrOp > ScalableMaskedUDivIOpLowering
OneToOneConvertToLLVMPattern< UsmmlaOp, UsmmlaIntrOp > UsmmlaOpLowering
OneToOneConvertToLLVMPattern< SmmlaOp, SmmlaIntrOp > SmmlaOpLowering
OneToOneConvertToLLVMPattern< ScalableMaskedDivFOp, ScalableMaskedDivFIntrOp > ScalableMaskedDivFOpLowering
OneToOneConvertToLLVMPattern< FmlaOp, FmlaIntrOp > FmlaOpLowering
OneToOneConvertToLLVMPattern< DupQLaneOp, DupQLaneIntrOp > DupQLaneLowering
OneToOneConvertToLLVMPattern< ScalableMaskedSDivIOp, ScalableMaskedSDivIIntrOp > ScalableMaskedSDivIOpLowering
OneToOneConvertToLLVMPattern< ScalableMaskedAddIOp, ScalableMaskedAddIIntrOp > ScalableMaskedAddIOpLowering
OneToOneConvertToLLVMPattern< UdotOp, UdotIntrOp > UdotOpLowering
OneToOneConvertToLLVMPattern< ScalableMaskedSubIOp, ScalableMaskedSubIIntrOp > ScalableMaskedSubIOpLowering
OneToOneConvertToLLVMPattern< ScalableMaskedSubFOp, ScalableMaskedSubFIntrOp > ScalableMaskedSubFOpLowering
Utility class for operation conversions targeting the LLVM dialect that match exactly one source oper...
Definition Pattern.h:233
ConvertOpToLLVMPattern(const LLVMTypeConverter &typeConverter, PatternBenefit benefit=1)
Definition Pattern.h:239
Derived class that automatically populates legalization information for different LLVM ops.
Conversion from types to the LLVM IR dialect.
Generic implementation of one-to-one conversion from "SourceOp" to "TargetOp" where the latter belong...
Definition Pattern.h:336
Location getLoc()
The source location the operation was defined or derived from.
This provides public APIs that all operations should have.
RewritePatternSet & add(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
A range-style iterator that allows for iterating over the offsets of all potential tiles of size tile...
This class provides an abstraction over the various different ranges of value types.
Definition TypeRange.h:40
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition Value.h:96
This is a builder type that keeps local references to arguments.
Builder & setDim(unsigned pos, int64_t val)
Set a dim in shape @pos to val.
Include the generated interface declarations.
void configureArmSVELegalizeForExportTarget(LLVMConversionTarget &target)
Configure the target to support lowering ArmSVE ops to ops that map to LLVM intrinsics.
Type getType(OpFoldResult ofr)
Returns the int type of the integer in ofr.
Definition Utils.cpp:311
void populateArmSVELegalizeForLLVMExportPatterns(const LLVMTypeConverter &converter, RewritePatternSet &patterns)
Collect a set of patterns to lower ArmSVE ops to ops that map to LLVM intrinsics.