@@ -139,7 +139,8 @@ class TypeConverter {
139
139
};
140
140
141
141
// / Register a conversion function. A conversion function must be convertible
142
- // / to any of the following forms (where `T` is a class derived from `Type`):
142
+ // / to any of the following forms (where `T` is `Value` or a class derived
143
+ // / from `Type`, including `Type` itself):
143
144
// /
144
145
// / * std::optional<Type>(T)
145
146
// / - This form represents a 1-1 type conversion. It should return nullptr
@@ -154,6 +155,14 @@ class TypeConverter {
154
155
// / `std::nullopt` is returned, the converter is allowed to try another
155
156
// / conversion function to perform the conversion.
156
157
// /
158
+ // / Conversion functions that accept `Value` as the first argument are
159
+ // / context-aware. I.e., they can take into account IR when converting the
160
+ // / type of the given value. Context-unaware conversion functions accept
161
+ // / `Type` or a derived class as the first argument.
162
+ // /
163
+ // / Note: Context-unaware conversions are cached, but context-aware
164
+ // / conversions are not.
165
+ // /
157
166
// / Note: When attempting to convert a type, e.g. via 'convertType', the
158
167
// / mostly recently added conversions will be invoked first.
159
168
template <typename FnT, typename T = typename llvm::function_traits<
@@ -242,15 +251,28 @@ class TypeConverter {
242
251
wrapTypeAttributeConversion<T, A>(std::forward<FnT>(callback)));
243
252
}
244
253
245
- // / Convert the given type. This function should return failure if no valid
254
+ // / Convert the given type. This function returns failure if no valid
246
255
// / conversion exists, success otherwise. If the new set of types is empty,
247
256
// / the type is removed and any usages of the existing value are expected to
248
257
// / be removed during conversion.
258
+ // /
259
+ // / Note: This overload invokes only context-unaware type conversion
260
+ // / functions. Users should call the other overload if possible.
249
261
LogicalResult convertType (Type t, SmallVectorImpl<Type> &results) const ;
250
262
263
+ // / Convert the type of the given value. This function returns failure if no
264
+ // / valid conversion exists, success otherwise. If the new set of types is
265
+ // / empty, the type is removed and any usages of the existing value are
266
+ // / expected to be removed during conversion.
267
+ // /
268
+ // / Note: This overload invokes both context-aware and context-unaware type
269
+ // / conversion functions.
270
+ LogicalResult convertType (Value v, SmallVectorImpl<Type> &results) const ;
271
+
251
272
// / This hook simplifies defining 1-1 type conversions. This function returns
252
273
// / the type to convert to on success, and a null type on failure.
253
274
Type convertType (Type t) const ;
275
+ Type convertType (Value v) const ;
254
276
255
277
// / Attempts a 1-1 type conversion, expecting the result type to be
256
278
// / `TargetType`. Returns the converted type cast to `TargetType` on success,
@@ -259,25 +281,36 @@ class TypeConverter {
259
281
TargetType convertType (Type t) const {
260
282
return dyn_cast_or_null<TargetType>(convertType (t));
261
283
}
284
+ template <typename TargetType>
285
+ TargetType convertType (Value v) const {
286
+ return dyn_cast_or_null<TargetType>(convertType (v));
287
+ }
262
288
263
- // / Convert the given set of types, filling 'results' as necessary. This
264
- // / returns failure if the conversion of any of the types fails, success
289
+ // / Convert the given types, filling 'results' as necessary. This returns
290
+ // / " failure" if the conversion of any of the types fails, " success"
265
291
// / otherwise.
266
292
LogicalResult convertTypes (TypeRange types,
267
293
SmallVectorImpl<Type> &results) const ;
268
294
295
+ // / Convert the types of the given values, filling 'results' as necessary.
296
+ // / This returns "failure" if the conversion of any of the types fails,
297
+ // / "success" otherwise.
298
+ LogicalResult convertTypes (ValueRange values,
299
+ SmallVectorImpl<Type> &results) const ;
300
+
269
301
// / Return true if the given type is legal for this type converter, i.e. the
270
302
// / type converts to itself.
271
303
bool isLegal (Type type) const ;
304
+ bool isLegal (Value value) const ;
272
305
273
306
// / Return true if all of the given types are legal for this type converter.
274
- template <typename RangeT>
275
- std::enable_if_t <!std::is_convertible<RangeT, Type>::value &&
276
- !std::is_convertible<RangeT, Operation *>::value,
277
- bool >
278
- isLegal (RangeT &&range) const {
307
+ bool isLegal (TypeRange range) const {
279
308
return llvm::all_of (range, [this ](Type type) { return isLegal (type); });
280
309
}
310
+ bool isLegal (ValueRange range) const {
311
+ return llvm::all_of (range, [this ](Value value) { return isLegal (value); });
312
+ }
313
+
281
314
// / Return true if the given operation has legal operand and result types.
282
315
bool isLegal (Operation *op) const ;
283
316
@@ -296,6 +329,11 @@ class TypeConverter {
296
329
LogicalResult convertSignatureArgs (TypeRange types,
297
330
SignatureConversion &result,
298
331
unsigned origInputOffset = 0 ) const ;
332
+ LogicalResult convertSignatureArg (unsigned inputNo, Value value,
333
+ SignatureConversion &result) const ;
334
+ LogicalResult convertSignatureArgs (ValueRange values,
335
+ SignatureConversion &result,
336
+ unsigned origInputOffset = 0 ) const ;
299
337
300
338
// / This function converts the type signature of the given block, by invoking
301
339
// / 'convertSignatureArg' for each argument. This function should return a
@@ -329,7 +367,7 @@ class TypeConverter {
329
367
// / types is empty, the type is removed and any usages of the existing value
330
368
// / are expected to be removed during conversion.
331
369
using ConversionCallbackFn = std::function<std::optional<LogicalResult>(
332
- Type, SmallVectorImpl<Type> &)>;
370
+ PointerUnion< Type, Value> , SmallVectorImpl<Type> &)>;
333
371
334
372
// / The signature of the callback used to materialize a source conversion.
335
373
// /
@@ -349,13 +387,14 @@ class TypeConverter {
349
387
350
388
// / Generate a wrapper for the given callback. This allows for accepting
351
389
// / different callback forms, that all compose into a single version.
352
- // / With callback of form: `std::optional<Type>(T)`
390
+ // / With callback of form: `std::optional<Type>(T)`, where `T` can be a
391
+ // / `Value` or a `Type` (or a class derived from `Type`).
353
392
template <typename T, typename FnT>
354
393
std::enable_if_t <std::is_invocable_v<FnT, T>, ConversionCallbackFn>
355
- wrapCallback (FnT &&callback) const {
394
+ wrapCallback (FnT &&callback) {
356
395
return wrapCallback<T>([callback = std::forward<FnT>(callback)](
357
- T type , SmallVectorImpl<Type> &results) {
358
- if (std::optional<Type> resultOpt = callback (type )) {
396
+ T typeOrValue , SmallVectorImpl<Type> &results) {
397
+ if (std::optional<Type> resultOpt = callback (typeOrValue )) {
359
398
bool wasSuccess = static_cast <bool >(*resultOpt);
360
399
if (wasSuccess)
361
400
results.push_back (*resultOpt);
@@ -365,20 +404,49 @@ class TypeConverter {
365
404
});
366
405
}
367
406
// / With callback of form: `std::optional<LogicalResult>(
368
- // / T, SmallVectorImpl<Type> &, ArrayRef<Type>)` .
407
+ // / T, SmallVectorImpl<Type> &)`, where `T` is a type .
369
408
template <typename T, typename FnT>
370
- std::enable_if_t <std::is_invocable_v<FnT, T, SmallVectorImpl<Type> &>,
409
+ std::enable_if_t <std::is_invocable_v<FnT, T, SmallVectorImpl<Type> &> &&
410
+ std::is_base_of_v<Type, T>,
371
411
ConversionCallbackFn>
372
412
wrapCallback (FnT &&callback) const {
373
413
return [callback = std::forward<FnT>(callback)](
374
- Type type ,
414
+ PointerUnion< Type, Value> typeOrValue ,
375
415
SmallVectorImpl<Type> &results) -> std::optional<LogicalResult> {
376
- T derivedType = dyn_cast<T>(type);
416
+ T derivedType;
417
+ if (Type t = dyn_cast<Type>(typeOrValue)) {
418
+ derivedType = dyn_cast<T>(t);
419
+ } else if (Value v = dyn_cast<Value>(typeOrValue)) {
420
+ derivedType = dyn_cast<T>(v.getType ());
421
+ } else {
422
+ llvm_unreachable (" unexpected variant" );
423
+ }
377
424
if (!derivedType)
378
425
return std::nullopt;
379
426
return callback (derivedType, results);
380
427
};
381
428
}
429
+ // / With callback of form: `std::optional<LogicalResult>(
430
+ // / T, SmallVectorImpl<Type>)`, where `T` is a `Value`.
431
+ template <typename T, typename FnT>
432
+ std::enable_if_t <std::is_invocable_v<FnT, T, SmallVectorImpl<Type> &> &&
433
+ std::is_same_v<T, Value>,
434
+ ConversionCallbackFn>
435
+ wrapCallback (FnT &&callback) {
436
+ hasContextAwareTypeConversions = true ;
437
+ return [callback = std::forward<FnT>(callback)](
438
+ PointerUnion<Type, Value> typeOrValue,
439
+ SmallVectorImpl<Type> &results) -> std::optional<LogicalResult> {
440
+ if (Type t = dyn_cast<Type>(typeOrValue)) {
441
+ // Context-aware type conversion was called with a type.
442
+ return std::nullopt;
443
+ } else if (Value v = dyn_cast<Value>(typeOrValue)) {
444
+ return callback (v, results);
445
+ }
446
+ llvm_unreachable (" unexpected variant" );
447
+ return std::nullopt;
448
+ };
449
+ }
382
450
383
451
// / Register a type conversion.
384
452
void registerConversion (ConversionCallbackFn callback) {
@@ -505,6 +573,12 @@ class TypeConverter {
505
573
mutable DenseMap<Type, SmallVector<Type, 2 >> cachedMultiConversions;
506
574
// / A mutex used for cache access
507
575
mutable llvm::sys::SmartRWMutex<true > cacheMutex;
576
+ // / Whether the type converter has context-aware type conversions. I.e.,
577
+ // / conversion rules that depend on the SSA value instead of just the type.
578
+ // / Type conversion caching is deactivated when there are context-aware
579
+ // / conversions because the type converter may return different results for
580
+ // / the same input type.
581
+ bool hasContextAwareTypeConversions = false ;
508
582
};
509
583
510
584
// ===----------------------------------------------------------------------===//
0 commit comments