MLIR 24.0.0git
IndexToLLVM.cpp
Go to the documentation of this file.
1//===- IndexToLLVM.cpp - Index to LLVM dialect conversion -------*- C++ -*-===//
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
10
18#include "mlir/Pass/Pass.h"
19
20using namespace mlir;
21using namespace index;
22
23namespace {
24
25//===----------------------------------------------------------------------===//
26// ConvertIndexCeilDivS
27//===----------------------------------------------------------------------===//
28
29/// Convert `ceildivs(n, m)` into `x = m > 0 ? -1 : 1` and then
30/// `n*m > 0 ? (n+x)/m + 1 : -(-n/m)`.
31struct ConvertIndexCeilDivS : mlir::ConvertOpToLLVMPattern<CeilDivSOp> {
33
34 LogicalResult
35 matchAndRewrite(CeilDivSOp op, CeilDivSOpAdaptor adaptor,
36 ConversionPatternRewriter &rewriter) const override {
37 Location loc = op.getLoc();
38 Value n = adaptor.getLhs();
39 Value m = adaptor.getRhs();
40 Value zero = LLVM::ConstantOp::create(rewriter, loc, n.getType(), 0);
41 Value posOne = LLVM::ConstantOp::create(rewriter, loc, n.getType(), 1);
42 Value negOne = LLVM::ConstantOp::create(rewriter, loc, n.getType(), -1);
43
44 // Compute `x`.
45 Value mPos =
46 LLVM::ICmpOp::create(rewriter, loc, LLVM::ICmpPredicate::sgt, m, zero);
47 Value x = LLVM::SelectOp::create(rewriter, loc, mPos, negOne, posOne);
48
49 // Compute the positive result.
50 Value nPlusX = LLVM::AddOp::create(rewriter, loc, n, x);
51 Value nPlusXDivM = LLVM::SDivOp::create(rewriter, loc, nPlusX, m);
52 Value posRes = LLVM::AddOp::create(rewriter, loc, nPlusXDivM, posOne);
53
54 // Compute the negative result.
55 Value negN = LLVM::SubOp::create(rewriter, loc, zero, n);
56 Value negNDivM = LLVM::SDivOp::create(rewriter, loc, negN, m);
57 Value negRes = LLVM::SubOp::create(rewriter, loc, zero, negNDivM);
58
59 // Pick the positive result if `n` and `m` have the same sign and `n` is
60 // non-zero, i.e. `(n > 0) == (m > 0) && n != 0`.
61 Value nPos =
62 LLVM::ICmpOp::create(rewriter, loc, LLVM::ICmpPredicate::sgt, n, zero);
63 Value sameSign = LLVM::ICmpOp::create(rewriter, loc,
64 LLVM::ICmpPredicate::eq, nPos, mPos);
65 Value nNonZero =
66 LLVM::ICmpOp::create(rewriter, loc, LLVM::ICmpPredicate::ne, n, zero);
67 Value cmp = LLVM::AndOp::create(rewriter, loc, sameSign, nNonZero);
68 rewriter.replaceOpWithNewOp<LLVM::SelectOp>(op, cmp, posRes, negRes);
69 return success();
70 }
71};
72
73//===----------------------------------------------------------------------===//
74// ConvertIndexCeilDivU
75//===----------------------------------------------------------------------===//
76
77/// Convert `ceildivu(n, m)` into `n == 0 ? 0 : (n-1)/m + 1`.
78struct ConvertIndexCeilDivU : mlir::ConvertOpToLLVMPattern<CeilDivUOp> {
80
81 LogicalResult
82 matchAndRewrite(CeilDivUOp op, CeilDivUOpAdaptor adaptor,
83 ConversionPatternRewriter &rewriter) const override {
84 Location loc = op.getLoc();
85 Value n = adaptor.getLhs();
86 Value m = adaptor.getRhs();
87 Value zero = LLVM::ConstantOp::create(rewriter, loc, n.getType(), 0);
88 Value one = LLVM::ConstantOp::create(rewriter, loc, n.getType(), 1);
89
90 // Compute the non-zero result.
91 Value minusOne = LLVM::SubOp::create(rewriter, loc, n, one);
92 Value quotient = LLVM::UDivOp::create(rewriter, loc, minusOne, m);
93 Value plusOne = LLVM::AddOp::create(rewriter, loc, quotient, one);
94
95 // Pick the result.
96 Value cmp =
97 LLVM::ICmpOp::create(rewriter, loc, LLVM::ICmpPredicate::eq, n, zero);
98 rewriter.replaceOpWithNewOp<LLVM::SelectOp>(op, cmp, zero, plusOne);
99 return success();
100 }
101};
102
103//===----------------------------------------------------------------------===//
104// ConvertIndexFloorDivS
105//===----------------------------------------------------------------------===//
106
107/// Convert `floordivs(n, m)` into `x = m < 0 ? 1 : -1` and then
108/// `n*m < 0 ? -1 - (x-n)/m : n/m`.
109struct ConvertIndexFloorDivS : mlir::ConvertOpToLLVMPattern<FloorDivSOp> {
111
112 LogicalResult
113 matchAndRewrite(FloorDivSOp op, FloorDivSOpAdaptor adaptor,
114 ConversionPatternRewriter &rewriter) const override {
115 Location loc = op.getLoc();
116 Value n = adaptor.getLhs();
117 Value m = adaptor.getRhs();
118 Value zero = LLVM::ConstantOp::create(rewriter, loc, n.getType(), 0);
119 Value posOne = LLVM::ConstantOp::create(rewriter, loc, n.getType(), 1);
120 Value negOne = LLVM::ConstantOp::create(rewriter, loc, n.getType(), -1);
121
122 // Compute `x`.
123 Value mNeg =
124 LLVM::ICmpOp::create(rewriter, loc, LLVM::ICmpPredicate::slt, m, zero);
125 Value x = LLVM::SelectOp::create(rewriter, loc, mNeg, posOne, negOne);
126
127 // Compute the negative result.
128 Value xMinusN = LLVM::SubOp::create(rewriter, loc, x, n);
129 Value xMinusNDivM = LLVM::SDivOp::create(rewriter, loc, xMinusN, m);
130 Value negRes = LLVM::SubOp::create(rewriter, loc, negOne, xMinusNDivM);
131
132 // Compute the positive result.
133 Value posRes = LLVM::SDivOp::create(rewriter, loc, n, m);
134
135 // Pick the negative result if `n` and `m` have different signs and `n` is
136 // non-zero, i.e. `(n < 0) != (m < 0) && n != 0`.
137 Value nNeg =
138 LLVM::ICmpOp::create(rewriter, loc, LLVM::ICmpPredicate::slt, n, zero);
139 Value diffSign = LLVM::ICmpOp::create(rewriter, loc,
140 LLVM::ICmpPredicate::ne, nNeg, mNeg);
141 Value nNonZero =
142 LLVM::ICmpOp::create(rewriter, loc, LLVM::ICmpPredicate::ne, n, zero);
143 Value cmp = LLVM::AndOp::create(rewriter, loc, diffSign, nNonZero);
144 rewriter.replaceOpWithNewOp<LLVM::SelectOp>(op, cmp, negRes, posRes);
145 return success();
146 }
147};
148
149//===----------------------------------------------------------------------===//
150// CovnertIndexCast
151//===----------------------------------------------------------------------===//
152
153/// Convert a cast op. If the materialized index type is the same as the other
154/// type, fold away the op. Otherwise, truncate or extend the op as appropriate.
155/// Signed casts sign extend when the result bitwidth is larger. Unsigned casts
156/// zero extend when the result bitwidth is larger.
157template <typename CastOp, typename ExtOp>
158struct ConvertIndexCast : public mlir::ConvertOpToLLVMPattern<CastOp> {
159 using mlir::ConvertOpToLLVMPattern<CastOp>::ConvertOpToLLVMPattern;
160
161 LogicalResult
162 matchAndRewrite(CastOp op, typename CastOp::Adaptor adaptor,
163 ConversionPatternRewriter &rewriter) const override {
164 Type in = adaptor.getInput().getType();
165 Type out = this->getTypeConverter()->convertType(op.getType());
166 if (in == out)
167 rewriter.replaceOp(op, adaptor.getInput());
168 else if (in.getIntOrFloatBitWidth() > out.getIntOrFloatBitWidth())
169 rewriter.replaceOpWithNewOp<LLVM::TruncOp>(op, out, adaptor.getInput());
170 else
171 rewriter.replaceOpWithNewOp<ExtOp>(op, out, adaptor.getInput());
172 return success();
173 }
174};
175
176using ConvertIndexCastS = ConvertIndexCast<CastSOp, LLVM::SExtOp>;
177using ConvertIndexCastU = ConvertIndexCast<CastUOp, LLVM::ZExtOp>;
178
179//===----------------------------------------------------------------------===//
180// ConvertIndexCmp
181//===----------------------------------------------------------------------===//
182
183/// Assert that the LLVM comparison enum lines up with index's enum.
184static constexpr bool checkPredicates(LLVM::ICmpPredicate lhs,
185 IndexCmpPredicate rhs) {
186 return static_cast<int>(lhs) == static_cast<int>(rhs);
187}
188
189static_assert(
190 LLVM::getMaxEnumValForICmpPredicate() ==
191 getMaxEnumValForIndexCmpPredicate() &&
192 checkPredicates(LLVM::ICmpPredicate::eq, IndexCmpPredicate::EQ) &&
193 checkPredicates(LLVM::ICmpPredicate::ne, IndexCmpPredicate::NE) &&
194 checkPredicates(LLVM::ICmpPredicate::sge, IndexCmpPredicate::SGE) &&
195 checkPredicates(LLVM::ICmpPredicate::sgt, IndexCmpPredicate::SGT) &&
196 checkPredicates(LLVM::ICmpPredicate::sle, IndexCmpPredicate::SLE) &&
197 checkPredicates(LLVM::ICmpPredicate::slt, IndexCmpPredicate::SLT) &&
198 checkPredicates(LLVM::ICmpPredicate::uge, IndexCmpPredicate::UGE) &&
199 checkPredicates(LLVM::ICmpPredicate::ugt, IndexCmpPredicate::UGT) &&
200 checkPredicates(LLVM::ICmpPredicate::ule, IndexCmpPredicate::ULE) &&
201 checkPredicates(LLVM::ICmpPredicate::ult, IndexCmpPredicate::ULT),
202 "LLVM ICmpPredicate mismatches IndexCmpPredicate");
203
204struct ConvertIndexCmp : public mlir::ConvertOpToLLVMPattern<CmpOp> {
206
207 LogicalResult
208 matchAndRewrite(CmpOp op, CmpOpAdaptor adaptor,
209 ConversionPatternRewriter &rewriter) const override {
210 // The LLVM enum has the same values as the index predicate enums.
211 rewriter.replaceOpWithNewOp<LLVM::ICmpOp>(
212 op, *LLVM::symbolizeICmpPredicate(static_cast<uint32_t>(op.getPred())),
213 adaptor.getLhs(), adaptor.getRhs());
214 return success();
215 }
216};
217
218//===----------------------------------------------------------------------===//
219// ConvertIndexSizeOf
220//===----------------------------------------------------------------------===//
221
222/// Lower `index.sizeof` to a constant with the value of the index bitwidth.
223struct ConvertIndexSizeOf : public mlir::ConvertOpToLLVMPattern<SizeOfOp> {
225
226 LogicalResult
227 matchAndRewrite(SizeOfOp op, SizeOfOpAdaptor adaptor,
228 ConversionPatternRewriter &rewriter) const override {
229 rewriter.replaceOpWithNewOp<LLVM::ConstantOp>(
230 op, getTypeConverter()->getIndexType(),
231 getTypeConverter()->getIndexTypeBitwidth());
232 return success();
233 }
234};
235
236//===----------------------------------------------------------------------===//
237// ConvertIndexConstant
238//===----------------------------------------------------------------------===//
239
240/// Convert an index constant. Truncate the value as appropriate.
241struct ConvertIndexConstant : public mlir::ConvertOpToLLVMPattern<ConstantOp> {
243
244 LogicalResult
245 matchAndRewrite(ConstantOp op, ConstantOpAdaptor adaptor,
246 ConversionPatternRewriter &rewriter) const override {
247 Type type = getTypeConverter()->getIndexType();
248 APInt value = op.getValue().trunc(type.getIntOrFloatBitWidth());
249 rewriter.replaceOpWithNewOp<LLVM::ConstantOp>(
250 op, type, IntegerAttr::get(type, value));
251 return success();
252 }
253};
254
255//===----------------------------------------------------------------------===//
256// Trivial Conversions
257//===----------------------------------------------------------------------===//
258
262using ConvertIndexDivS =
264using ConvertIndexDivU =
266using ConvertIndexRemS =
268using ConvertIndexRemU =
270using ConvertIndexMaxS =
272using ConvertIndexMaxU =
274using ConvertIndexMinS =
276using ConvertIndexMinU =
279using ConvertIndexShrS =
281using ConvertIndexShrU =
286using ConvertIndexBoolConstant =
288
289} // namespace
290
291//===----------------------------------------------------------------------===//
292// Pattern Population
293//===----------------------------------------------------------------------===//
294
296 const LLVMTypeConverter &typeConverter, RewritePatternSet &patterns) {
297 patterns.insert<
298 // clang-format off
299 ConvertIndexAdd,
300 ConvertIndexSub,
301 ConvertIndexMul,
302 ConvertIndexDivS,
303 ConvertIndexDivU,
304 ConvertIndexRemS,
305 ConvertIndexRemU,
306 ConvertIndexMaxS,
307 ConvertIndexMaxU,
308 ConvertIndexMinS,
309 ConvertIndexMinU,
310 ConvertIndexShl,
311 ConvertIndexShrS,
312 ConvertIndexShrU,
313 ConvertIndexAnd,
314 ConvertIndexOr,
315 ConvertIndexXor,
316 ConvertIndexCeilDivS,
317 ConvertIndexCeilDivU,
318 ConvertIndexFloorDivS,
319 ConvertIndexCastS,
320 ConvertIndexCastU,
321 ConvertIndexCmp,
322 ConvertIndexSizeOf,
323 ConvertIndexConstant,
324 ConvertIndexBoolConstant
325 // clang-format on
326 >(typeConverter);
327}
328
329//===----------------------------------------------------------------------===//
330// ODS-Generated Definitions
331//===----------------------------------------------------------------------===//
332
333namespace mlir {
334#define GEN_PASS_DEF_CONVERTINDEXTOLLVMPASS
335#include "mlir/Conversion/Passes.h.inc"
336} // namespace mlir
337
338//===----------------------------------------------------------------------===//
339// Pass Definition
340//===----------------------------------------------------------------------===//
341
342namespace {
343struct ConvertIndexToLLVMPass
344 : public impl::ConvertIndexToLLVMPassBase<ConvertIndexToLLVMPass> {
345 using Base::Base;
346
347 void runOnOperation() override;
348};
349} // namespace
350
351void ConvertIndexToLLVMPass::runOnOperation() {
352 // Configure dialect conversion.
353 ConversionTarget target(getContext());
354 target.addIllegalDialect<IndexDialect>();
355 target.addLegalDialect<LLVM::LLVMDialect>();
356
357 // Set LLVM lowering options.
358 const auto &dataLayoutAnalysis = getAnalysis<DataLayoutAnalysis>();
359 LowerToLLVMOptions options(&getContext(),
360 dataLayoutAnalysis.getAtOrAbove(getOperation()));
361 if (indexBitwidth != kDeriveIndexBitwidthFromDataLayout)
362 options.overrideIndexBitwidth(indexBitwidth);
363 LLVMTypeConverter typeConverter(&getContext(), options, &dataLayoutAnalysis);
364
365 // Populate patterns and run the conversion.
366 RewritePatternSet patterns(&getContext());
367 populateIndexToLLVMConversionPatterns(typeConverter, patterns);
368
369 if (failed(
370 applyPartialConversion(getOperation(), target, std::move(patterns))))
371 return signalPassFailure();
372}
373
374//===----------------------------------------------------------------------===//
375// ConvertToLLVMPatternInterface implementation
376//===----------------------------------------------------------------------===//
377
378namespace {
379/// Implement the interface to convert Index to LLVM.
380struct IndexToLLVMDialectInterface : public ConvertToLLVMPatternInterface {
381 IndexToLLVMDialectInterface(Dialect *dialect)
382 : ConvertToLLVMPatternInterface(dialect) {}
383
384 void loadDependentDialects(MLIRContext *context) const final {
385 context->loadDialect<LLVM::LLVMDialect>();
386 }
387
388 /// Hook for derived dialect interface to provide conversion patterns
389 /// and mark dialect legal for the conversion target.
390 void populateConvertToLLVMConversionPatterns(
391 ConversionTarget &target, LLVMTypeConverter &typeConverter,
392 RewritePatternSet &patterns) const final {
393 populateIndexToLLVMConversionPatterns(typeConverter, patterns);
394 }
395};
396} // namespace
397
399 DialectRegistry &registry) {
400 registry.addExtension(+[](MLIRContext *ctx, index::IndexDialect *dialect) {
401 dialect->addInterfaces<IndexToLLVMDialectInterface>();
402 });
403}
return success()
b getContext())
static llvm::ManagedStatic< PassManagerOptions > options
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
Type getIndexType() const
Gets the MLIR type wrapping the LLVM integer type whose bit width is defined by the used type convert...
Definition Pattern.cpp:38
The DialectRegistry maps a dialect namespace to a constructor for the matching dialect.
bool addExtension(TypeID extensionID, std::unique_ptr< DialectExtensionBase > extension)
Add the given extension to the registry.
Conversion from types to the LLVM IR dialect.
MLIRContext is the top-level object for a collection of MLIR operations.
Definition MLIRContext.h:71
Generic implementation of one-to-one conversion from "SourceOp" to "TargetOp" where the latter belong...
Definition Pattern.h:336
RewritePatternSet & insert(ConstructorArg &&arg, ConstructorArgs &&...args)
Add an instance of each of the pattern types 'Ts' to the pattern list with the given arguments.
unsigned getIntOrFloatBitWidth() const
Return the bit width of an integer or a float type, assert failure on other types.
Definition Types.cpp:124
Type getType() const
Return the type of this value.
Definition Value.h:105
void populateIndexToLLVMConversionPatterns(const LLVMTypeConverter &converter, RewritePatternSet &patterns)
void registerConvertIndexToLLVMInterface(DialectRegistry &registry)
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:853
Include the generated interface declarations.
static constexpr unsigned kDeriveIndexBitwidthFromDataLayout
Value to pass as bitwidth for the index type when the converter is expected to derive the bitwidth fr...