@@ -139,7 +139,8 @@ class TypeConverter {
139139 };
140140
141141 // / 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):
143144 // /
144145 // / * std::optional<Type>(T)
145146 // / - This form represents a 1-1 type conversion. It should return nullptr
@@ -154,6 +155,14 @@ class TypeConverter {
154155 // / `std::nullopt` is returned, the converter is allowed to try another
155156 // / conversion function to perform the conversion.
156157 // /
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+ // /
157166 // / Note: When attempting to convert a type, e.g. via 'convertType', the
158167 // / mostly recently added conversions will be invoked first.
159168 template <typename FnT, typename T = typename llvm::function_traits<
@@ -242,15 +251,28 @@ class TypeConverter {
242251 wrapTypeAttributeConversion<T, A>(std::forward<FnT>(callback)));
243252 }
244253
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
246255 // / conversion exists, success otherwise. If the new set of types is empty,
247256 // / the type is removed and any usages of the existing value are expected to
248257 // / 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.
249261 LogicalResult convertType (Type t, SmallVectorImpl<Type> &results) const ;
250262
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+
251272 // / This hook simplifies defining 1-1 type conversions. This function returns
252273 // / the type to convert to on success, and a null type on failure.
253274 Type convertType (Type t) const ;
275+ Type convertType (Value v) const ;
254276
255277 // / Attempts a 1-1 type conversion, expecting the result type to be
256278 // / `TargetType`. Returns the converted type cast to `TargetType` on success,
@@ -259,25 +281,36 @@ class TypeConverter {
259281 TargetType convertType (Type t) const {
260282 return dyn_cast_or_null<TargetType>(convertType (t));
261283 }
284+ template <typename TargetType>
285+ TargetType convertType (Value v) const {
286+ return dyn_cast_or_null<TargetType>(convertType (v));
287+ }
262288
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"
265291 // / otherwise.
266292 LogicalResult convertTypes (TypeRange types,
267293 SmallVectorImpl<Type> &results) const ;
268294
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+
269301 // / Return true if the given type is legal for this type converter, i.e. the
270302 // / type converts to itself.
271303 bool isLegal (Type type) const ;
304+ bool isLegal (Value value) const ;
272305
273306 // / 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 {
279308 return llvm::all_of (range, [this ](Type type) { return isLegal (type); });
280309 }
310+ bool isLegal (ValueRange range) const {
311+ return llvm::all_of (range, [this ](Value value) { return isLegal (value); });
312+ }
313+
281314 // / Return true if the given operation has legal operand and result types.
282315 bool isLegal (Operation *op) const ;
283316
@@ -296,6 +329,11 @@ class TypeConverter {
296329 LogicalResult convertSignatureArgs (TypeRange types,
297330 SignatureConversion &result,
298331 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 ;
299337
300338 // / This function converts the type signature of the given block, by invoking
301339 // / 'convertSignatureArg' for each argument. This function should return a
@@ -329,7 +367,7 @@ class TypeConverter {
329367 // / types is empty, the type is removed and any usages of the existing value
330368 // / are expected to be removed during conversion.
331369 using ConversionCallbackFn = std::function<std::optional<LogicalResult>(
332- Type, SmallVectorImpl<Type> &)>;
370+ PointerUnion< Type, Value> , SmallVectorImpl<Type> &)>;
333371
334372 // / The signature of the callback used to materialize a source conversion.
335373 // /
@@ -349,13 +387,14 @@ class TypeConverter {
349387
350388 // / Generate a wrapper for the given callback. This allows for accepting
351389 // / 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`).
353392 template <typename T, typename FnT>
354393 std::enable_if_t <std::is_invocable_v<FnT, T>, ConversionCallbackFn>
355- wrapCallback (FnT &&callback) const {
394+ wrapCallback (FnT &&callback) {
356395 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 )) {
359398 bool wasSuccess = static_cast <bool >(*resultOpt);
360399 if (wasSuccess)
361400 results.push_back (*resultOpt);
@@ -365,20 +404,49 @@ class TypeConverter {
365404 });
366405 }
367406 // / With callback of form: `std::optional<LogicalResult>(
368- // / T, SmallVectorImpl<Type> &, ArrayRef<Type>)` .
407+ // / T, SmallVectorImpl<Type> &)`, where `T` is a type .
369408 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>,
371411 ConversionCallbackFn>
372412 wrapCallback (FnT &&callback) const {
373413 return [callback = std::forward<FnT>(callback)](
374- Type type ,
414+ PointerUnion< Type, Value> typeOrValue ,
375415 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+ }
377424 if (!derivedType)
378425 return std::nullopt ;
379426 return callback (derivedType, results);
380427 };
381428 }
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+ }
382450
383451 // / Register a type conversion.
384452 void registerConversion (ConversionCallbackFn callback) {
@@ -505,6 +573,12 @@ class TypeConverter {
505573 mutable DenseMap<Type, SmallVector<Type, 2 >> cachedMultiConversions;
506574 // / A mutex used for cache access
507575 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 ;
508582};
509583
510584// ===----------------------------------------------------------------------===//
0 commit comments