Skip to content

Commit d3e7bdd

Browse files
authored
[TorchToTosa] Fix AtenWhereSelfOp lowering (#4608)
Cast the `self` and `other` operands of `aten.where.self` to the converted result element type before lowering to `tosa.select`. The result type has already been inferred using pytorch type promotion rules. `tosa.select` requires both `self` and `other` operands to match the element dtype of the result. Without these casts, mixed dtype `where` inputs can produce invalid tosa.
1 parent f015e44 commit d3e7bdd

3 files changed

Lines changed: 135 additions & 5 deletions

File tree

lib/Conversion/TorchToTosa/TorchToTosa.cpp

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6249,14 +6249,39 @@ LogicalResult ConvertAtenOp<AtenWhereSelfOp>::matchAndRewriteImpl(
62496249

62506250
auto outType =
62516251
dyn_cast<TensorType>(getTypeConverter()->convertType(op.getType()));
6252+
if (!outType)
6253+
return rewriter.notifyMatchFailure(op, "expected tensor result type");
6254+
6255+
auto outElemTy = outType.getElementType();
6256+
Value selfCast = self;
6257+
Value otherCast = other;
62526258

6253-
if (mlir::tosa::EqualizeRanks(rewriter, op->getLoc(), cond, self).failed() ||
6254-
mlir::tosa::EqualizeRanks(rewriter, op->getLoc(), cond, other).failed() ||
6255-
mlir::tosa::EqualizeRanks(rewriter, op->getLoc(), self, other).failed())
6259+
if (selfType.getElementType() != outElemTy) {
6260+
auto maybeCast =
6261+
tosa::tosaCastTensorToType(rewriter, self, selfType.clone(outElemTy));
6262+
if (!maybeCast)
6263+
return rewriter.notifyMatchFailure(op, "failed to cast tensor to dtype");
6264+
selfCast = *maybeCast;
6265+
}
6266+
if (otherType.getElementType() != outElemTy) {
6267+
auto maybeCast =
6268+
tosa::tosaCastTensorToType(rewriter, other, otherType.clone(outElemTy));
6269+
if (!maybeCast)
6270+
return rewriter.notifyMatchFailure(op, "failed to cast tensor to dtype");
6271+
otherCast = *maybeCast;
6272+
}
6273+
6274+
if (mlir::tosa::EqualizeRanks(rewriter, op->getLoc(), cond, selfCast)
6275+
.failed() ||
6276+
mlir::tosa::EqualizeRanks(rewriter, op->getLoc(), cond, otherCast)
6277+
.failed() ||
6278+
mlir::tosa::EqualizeRanks(rewriter, op->getLoc(), selfCast, otherCast)
6279+
.failed())
62566280
return rewriter.notifyMatchFailure(
62576281
op, "Failed to equalize ranks among operands and result");
62586282

6259-
rewriter.replaceOpWithNewOp<tosa::SelectOp>(op, outType, cond, self, other);
6283+
rewriter.replaceOpWithNewOp<tosa::SelectOp>(op, outType, cond, selfCast,
6284+
otherCast);
62606285

62616286
return success();
62626287
}

projects/pt1/python/torch_mlir_e2e_test/test_suite/elementwise.py

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,68 @@ def ElementwiseAtenWhereSelfModule_basic(module, tu: TestUtils):
466466
# ==============================================================================
467467

468468

469+
class ElementwiseAtenWhereSelfDifferentDtypeModule(torch.nn.Module):
470+
def __init__(self):
471+
super().__init__()
472+
473+
@export
474+
@annotate_args(
475+
[
476+
None,
477+
([1, 1, 5, 5], torch.bool, True),
478+
([1, 12, 5, 5], torch.int64, True),
479+
([1, 12, 5, 5], torch.int32, True),
480+
]
481+
)
482+
def forward(self, a, b, c):
483+
return torch.ops.aten.where(a, b, c)
484+
485+
486+
@register_test_case(
487+
module_factory=lambda: ElementwiseAtenWhereSelfDifferentDtypeModule()
488+
)
489+
def ElementwiseAtenWhereSelfDifferentDtypeModule_basic(module, tu: TestUtils):
490+
module.forward(
491+
torch.zeros(1, 1, 5, 5, dtype=torch.bool),
492+
tu.randint(1, 12, 5, 5, dtype=torch.int64),
493+
tu.randint(1, 12, 5, 5, dtype=torch.int32),
494+
)
495+
496+
497+
# ==============================================================================
498+
499+
500+
class ElementwiseAtenWhereSelfDifferentDtypeAndRankModule(torch.nn.Module):
501+
def __init__(self):
502+
super().__init__()
503+
504+
@export
505+
@annotate_args(
506+
[
507+
None,
508+
([1, 1, 5, 5], torch.bool, True),
509+
([], torch.int64, True),
510+
([1, 12, 5, 5], torch.int32, True),
511+
]
512+
)
513+
def forward(self, a, b, c):
514+
return torch.ops.aten.where(a, b, c)
515+
516+
517+
@register_test_case(
518+
module_factory=lambda: ElementwiseAtenWhereSelfDifferentDtypeAndRankModule()
519+
)
520+
def ElementwiseAtenWhereSelfDifferentDtypeAndRankModule_basic(module, tu: TestUtils):
521+
module.forward(
522+
torch.zeros(1, 1, 5, 5, dtype=torch.bool),
523+
tu.randint(),
524+
tu.randint(1, 12, 5, 5, dtype=torch.int32),
525+
)
526+
527+
528+
# ==============================================================================
529+
530+
469531
class ElementwiseWhereSelfModule(torch.nn.Module):
470532
def __init__(self):
471533
super().__init__()

test/Conversion/TorchToTosa/basic.mlir

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1855,12 +1855,55 @@ func.func @torch.aten.where.self(%arg0: !torch.vtensor<[1,1,5,5],i1>, %arg1: !to
18551855
// CHECK: %[[VAL_11:.*]] = tosa.reshape %[[VAL_7]], %[[VAL_10]] : (tensor<1x1xf32>, !tosa.shape<6>) -> tensor<1x1x1x1x1x1xf32>
18561856
// CHECK: %[[VAL_12:.*]] = tosa.select %[[VAL_9]], %[[VAL_11]], %[[VAL_3]] : (tensor<1x1x1x1x5x4xi1>, tensor<1x1x1x1x1x1xf32>, tensor<1x3x1x1x5x4xf32>) -> tensor<1x3x1x1x5x4xf32>
18571857
// CHECK: %[[VAL_13:.*]] = torch_c.from_builtin_tensor %[[VAL_12]] : tensor<1x3x1x1x5x4xf32> -> !torch.vtensor<[1,3,1,1,5,4],f32>
1858-
// CHECK: return %[[VAL_13]]
1858+
// CHECK: return %[[VAL_13]] : !torch.vtensor<[1,3,1,1,5,4],f32>
1859+
// CHECK: }
18591860
func.func @torch.aten.where.self_differing_rank_inputs(%40: !torch.vtensor<[5,4],i1>, %41: !torch.vtensor<[],f32>, %38 : !torch.vtensor<[1,3,1,1,5,4],f32>) -> (!torch.vtensor<[1,3,1,1,5,4],f32>) {
18601861
%42 = torch.aten.where.self %40, %41, %38 : !torch.vtensor<[5,4],i1>, !torch.vtensor<[],f32>, !torch.vtensor<[1,3,1,1,5,4],f32> -> !torch.vtensor<[1,3,1,1,5,4],f32>
18611862
return %42: !torch.vtensor<[1,3,1,1,5,4],f32>
18621863
}
18631864

1865+
// -----
1866+
// CHECK-LABEL: func.func @torch.aten.where.self_differing_dtype_inputs(
1867+
// CHECK-SAME: %[[VAL_0:.*]]: !torch.vtensor<[1,1,5,5],i1>,
1868+
// CHECK-SAME: %[[VAL_1:.*]]: !torch.vtensor<[1,12,5,5],si32>,
1869+
// CHECK-SAME: %[[VAL_2:.*]]: !torch.vtensor<[1,12,5,5],si64>) -> !torch.vtensor<[1,12,5,5],si64> {
1870+
// CHECK: %[[VAL_3:.*]] = torch_c.to_builtin_tensor %[[VAL_2]] : !torch.vtensor<[1,12,5,5],si64> -> tensor<1x12x5x5xi64>
1871+
// CHECK: %[[VAL_4:.*]] = torch_c.to_builtin_tensor %[[VAL_1]] : !torch.vtensor<[1,12,5,5],si32> -> tensor<1x12x5x5xi32>
1872+
// CHECK: %[[VAL_5:.*]] = torch_c.to_builtin_tensor %[[VAL_0]] : !torch.vtensor<[1,1,5,5],i1> -> tensor<1x1x5x5xi1>
1873+
// CHECK: %[[VAL_6:.*]] = tosa.cast %[[VAL_4]] : (tensor<1x12x5x5xi32>) -> tensor<1x12x5x5xi64>
1874+
// CHECK: %[[VAL_7:.*]] = tosa.select %[[VAL_5]], %[[VAL_6]], %[[VAL_3]] : (tensor<1x1x5x5xi1>, tensor<1x12x5x5xi64>, tensor<1x12x5x5xi64>) -> tensor<1x12x5x5xi64>
1875+
// CHECK: %[[VAL_8:.*]] = torch_c.from_builtin_tensor %[[VAL_7]] : tensor<1x12x5x5xi64> -> !torch.vtensor<[1,12,5,5],si64>
1876+
// CHECK: return %[[VAL_8]] : !torch.vtensor<[1,12,5,5],si64>
1877+
// CHECK: }
1878+
func.func @torch.aten.where.self_differing_dtype_inputs(%arg0: !torch.vtensor<[1,1,5,5],i1>, %arg1: !torch.vtensor<[1,12,5,5],si32>, %arg2: !torch.vtensor<[1,12,5,5],si64>) -> !torch.vtensor<[1,12,5,5],si64> {
1879+
%0 = torch.aten.where.self %arg0, %arg1, %arg2 : !torch.vtensor<[1,1,5,5],i1>, !torch.vtensor<[1,12,5,5],si32>, !torch.vtensor<[1,12,5,5],si64> -> !torch.vtensor<[1,12,5,5],si64>
1880+
return %0 : !torch.vtensor<[1,12,5,5],si64>
1881+
}
1882+
1883+
// -----
1884+
// CHECK-LABEL: func.func @torch.aten.where.self_differing_dtype_and_rank_inputs(
1885+
// CHECK-SAME: %[[VAL_0:.*]]: !torch.vtensor<[5,4],i1>,
1886+
// CHECK-SAME: %[[VAL_1:.*]]: !torch.vtensor<[],si64>,
1887+
// CHECK-SAME: %[[VAL_2:.*]]: !torch.vtensor<[1,3,1,1,5,4],si32>) -> !torch.vtensor<[1,3,1,1,5,4],si32> {
1888+
// CHECK: %[[VAL_3:.*]] = torch_c.to_builtin_tensor %[[VAL_2]] : !torch.vtensor<[1,3,1,1,5,4],si32> -> tensor<1x3x1x1x5x4xi32>
1889+
// CHECK: %[[VAL_4:.*]] = torch_c.to_builtin_tensor %[[VAL_1]] : !torch.vtensor<[],si64> -> tensor<i64>
1890+
// CHECK: %[[VAL_5:.*]] = torch_c.to_builtin_tensor %[[VAL_0]] : !torch.vtensor<[5,4],i1> -> tensor<5x4xi1>
1891+
// CHECK: %[[VAL_6:.*]] = tosa.cast %[[VAL_4]] : (tensor<i64>) -> tensor<i32>
1892+
// CHECK: %[[VAL_7:.*]] = tosa.const_shape {values = dense<1> : tensor<2xindex>} : () -> !tosa.shape<2>
1893+
// CHECK: %[[VAL_8:.*]] = tosa.reshape %[[VAL_6]], %[[VAL_7]] : (tensor<i32>, !tosa.shape<2>) -> tensor<1x1xi32>
1894+
// CHECK: %[[VAL_9:.*]] = tosa.const_shape {values = dense<[1, 1, 1, 1, 5, 4]> : tensor<6xindex>} : () -> !tosa.shape<6>
1895+
// CHECK: %[[VAL_10:.*]] = tosa.reshape %[[VAL_5]], %[[VAL_9]] : (tensor<5x4xi1>, !tosa.shape<6>) -> tensor<1x1x1x1x5x4xi1>
1896+
// CHECK: %[[VAL_11:.*]] = tosa.const_shape {values = dense<1> : tensor<6xindex>} : () -> !tosa.shape<6>
1897+
// CHECK: %[[VAL_12:.*]] = tosa.reshape %[[VAL_8]], %[[VAL_11]] : (tensor<1x1xi32>, !tosa.shape<6>) -> tensor<1x1x1x1x1x1xi32>
1898+
// CHECK: %[[VAL_13:.*]] = tosa.select %[[VAL_10]], %[[VAL_12]], %[[VAL_3]] : (tensor<1x1x1x1x5x4xi1>, tensor<1x1x1x1x1x1xi32>, tensor<1x3x1x1x5x4xi32>) -> tensor<1x3x1x1x5x4xi32>
1899+
// CHECK: %[[VAL_14:.*]] = torch_c.from_builtin_tensor %[[VAL_13]] : tensor<1x3x1x1x5x4xi32> -> !torch.vtensor<[1,3,1,1,5,4],si32>
1900+
// CHECK: return %[[VAL_14]] : !torch.vtensor<[1,3,1,1,5,4],si32>
1901+
// CHECK: }
1902+
func.func @torch.aten.where.self_differing_dtype_and_rank_inputs(%arg0: !torch.vtensor<[5,4],i1>, %arg1: !torch.vtensor<[],si64>, %arg2: !torch.vtensor<[1,3,1,1,5,4],si32>) -> !torch.vtensor<[1,3,1,1,5,4],si32> {
1903+
%0 = torch.aten.where.self %arg0, %arg1, %arg2 : !torch.vtensor<[5,4],i1>, !torch.vtensor<[],si64>, !torch.vtensor<[1,3,1,1,5,4],si32> -> !torch.vtensor<[1,3,1,1,5,4],si32>
1904+
return %0 : !torch.vtensor<[1,3,1,1,5,4],si32>
1905+
}
1906+
18641907
// -----
18651908
// CHECK-LABEL: func.func @torch.aten.remainder.Scalar(
18661909
// CHECK-SAME: %[[VAL_0:.*]]: !torch.vtensor<[2,4],f32>) -> !torch.vtensor<[2,4],f32> {

0 commit comments

Comments
 (0)