Skip to content

Commit 823eda5

Browse files
[mlir][Transforms] Dialect conversion: Extra checks during replaceOp
This commit adds extra checks/assertions to the `ConversionPatternRewriterImpl::notifyOpReplaced` to improve its robustness. Replacing an `unrealized_conversion_cast` op that was created by the driver is forbidden and is now caught early during `replaceOp`. It may work in some cases, but is generally dangerous because the conversion driver keeps track of these ops. (Erasing is them is fine.) This change is also in preparation of a subsequent commit that splits the `ConversionValueMapping` into replacements and materializations (with the goal of simplifying block signature conversions). `null` replacement values are no longer registered in the `ConversionValueMapping`. This was an oversight in #106760. `null` values in the mapping could result in crashes when using the `ConversionValueMapping` API.
1 parent 16388fd commit 823eda5

File tree

1 file changed

+23
-8
lines changed

1 file changed

+23
-8
lines changed

mlir/lib/Transforms/Utils/DialectConversion.cpp

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1365,27 +1365,42 @@ void ConversionPatternRewriterImpl::notifyOpReplaced(Operation *op,
13651365
assert(newValues.size() == op->getNumResults());
13661366
assert(!ignoredOps.contains(op) && "operation was already replaced");
13671367

1368+
// Check if replaced op is an unresolved materialization, i.e., an
1369+
// unrealized_conversion_cast op that was created by the conversion driver.
1370+
bool isUnresolvedMaterialization = false;
1371+
if (auto castOp = dyn_cast<UnrealizedConversionCastOp>(op))
1372+
if (unresolvedMaterializations.contains(castOp))
1373+
isUnresolvedMaterialization = true;
1374+
13681375
// Create mappings for each of the new result values.
13691376
for (auto [newValue, result] : llvm::zip(newValues, op->getResults())) {
13701377
if (!newValue) {
13711378
// This result was dropped and no replacement value was provided.
1372-
if (auto castOp = dyn_cast<UnrealizedConversionCastOp>(op)) {
1373-
if (unresolvedMaterializations.contains(castOp)) {
1374-
// Do not create another materializations if we are erasing a
1375-
// materialization.
1376-
continue;
1377-
}
1379+
if (isUnresolvedMaterialization) {
1380+
// Do not create another materializations if we are erasing a
1381+
// materialization.
1382+
continue;
13781383
}
13791384

13801385
// Materialize a replacement value "out of thin air".
13811386
newValue = buildUnresolvedMaterialization(
13821387
MaterializationKind::Source, computeInsertPoint(result),
13831388
result.getLoc(), /*inputs=*/ValueRange(),
13841389
/*outputType=*/result.getType(), currentTypeConverter);
1390+
} else {
1391+
// Make sure that the user does not mess with unresolved materializations
1392+
// that were inserted by the conversion driver. We keep track of these
1393+
// ops in internal data structures. Erasing them must be allowed because
1394+
// this can happen when the user is erasing an entire block (including
1395+
// its body). But replacing them with another value should be forbidden
1396+
// to avoid problems with the `mapping`.
1397+
assert(!isUnresolvedMaterialization &&
1398+
"attempting to replace an unresolved materialization");
13851399
}
13861400

1387-
// Remap, and check for any result type changes.
1388-
mapping.map(result, newValue);
1401+
// Remap result to replacement value.
1402+
if (newValue)
1403+
mapping.map(result, newValue);
13891404
}
13901405

13911406
appendRewrite<ReplaceOperationRewrite>(op, currentTypeConverter);

0 commit comments

Comments
 (0)