|
| 1 | +// Modifications (c) Copyright 2026 Advanced Micro Devices, Inc. or its |
| 2 | +// affiliates |
| 3 | + |
| 4 | +// RUN: mlir-opt --split-input-file -canonicalize="test-convergence" %s | FileCheck %s |
| 5 | + |
| 6 | +// CHECK-LABEL: @negate_negate_quant_nofold |
| 7 | +// CHECK-NEXT: tosa.negate |
| 8 | +// CHECK-NEXT: tosa.negate |
| 9 | + |
| 10 | +// The output of negate should be clipped to the range of the storage type. |
| 11 | +// However, the canonicalization pass illegally removes the intermediate clip. |
| 12 | +// Thus, negate(negate(x)) = x is not valid when x carries a quant type. |
| 13 | +// A simple counter-example is neg(neg(-128)) = neg(127) = -127 != -128 |
| 14 | +func.func @negate_negate_quant_nofold(%arg0: tensor<4x!quant.uniform<i8:f32, 0.05>>) -> tensor<4x!quant.uniform<i8:f32, 0.05>> { |
| 15 | + %0 = tosa.negate %arg0 : (tensor<4x!quant.uniform<i8:f32, 0.05>>) -> tensor<4x!quant.uniform<i8:f32, 0.05>> |
| 16 | + %1 = tosa.negate %0 : (tensor<4x!quant.uniform<i8:f32, 0.05>>) -> tensor<4x!quant.uniform<i8:f32, 0.05>> |
| 17 | + return %1 : tensor<4x!quant.uniform<i8:f32, 0.05>> |
| 18 | +} |
| 19 | + |
| 20 | +// ----- |
| 21 | + |
| 22 | +// CHECK-LABEL: @exp_log_quant_nofold |
| 23 | +// CHECK-NEXT: tosa.exp |
| 24 | +// CHECK-NEXT: tosa.log |
| 25 | +func.func @exp_log_quant_nofold(%arg0: tensor<4x!quant.uniform<i8:f32, 0.05>>) -> tensor<4x!quant.uniform<i8:f32, 0.05>> { |
| 26 | + %0 = tosa.exp %arg0 : (tensor<4x!quant.uniform<i8:f32, 0.05>>) -> tensor<4x!quant.uniform<i8:f32, 0.05>> |
| 27 | + %1 = tosa.log %0 : (tensor<4x!quant.uniform<i8:f32, 0.05>>) -> tensor<4x!quant.uniform<i8:f32, 0.05>> |
| 28 | + return %1 : tensor<4x!quant.uniform<i8:f32, 0.05>> |
| 29 | +} |
| 30 | + |
| 31 | +// ----- |
| 32 | + |
| 33 | +// CHECK-LABEL: @log_exp_quant_nofold |
| 34 | +// CHECK-NEXT: tosa.log |
| 35 | +// CHECK-NEXT: tosa.exp |
| 36 | +func.func @log_exp_quant_nofold(%arg0: tensor<4x!quant.uniform<i8:f32, 0.05>>) -> tensor<4x!quant.uniform<i8:f32, 0.05>> { |
| 37 | + %0 = tosa.log %arg0 : (tensor<4x!quant.uniform<i8:f32, 0.05>>) -> tensor<4x!quant.uniform<i8:f32, 0.05>> |
| 38 | + %1 = tosa.exp %0 : (tensor<4x!quant.uniform<i8:f32, 0.05>>) -> tensor<4x!quant.uniform<i8:f32, 0.05>> |
| 39 | + return %1 : tensor<4x!quant.uniform<i8:f32, 0.05>> |
| 40 | +} |
| 41 | + |
| 42 | +// ----- |
| 43 | + |
| 44 | +// CHECK-LABEL: @min_to_clamp_quant |
| 45 | +// CHECK: tosa.clamp %arg0 {max_fp = 6.000000e+00 : f32, max_int = 6 : i64, |
| 46 | +// CHECK-SAME: min_fp = -3.40282347E+38 : f32, min_int = -2147483648 : i64} |
| 47 | +func.func @min_to_clamp_quant(%arg0: tensor<4x!quant.uniform<i8:f32, 0.05>>) -> tensor<4x!quant.uniform<i8:f32, 0.05>> { |
| 48 | + %0 = "tosa.const"() <{value = dense<6> : tensor<1xi8>}> : () -> tensor<1x!quant.uniform<i8:f32, 0.05>> |
| 49 | + %1 = tosa.minimum %arg0, %0 : (tensor<4x!quant.uniform<i8:f32, 0.05>>, tensor<1x!quant.uniform<i8:f32, 0.05>>) -> tensor<4x!quant.uniform<i8:f32, 0.05>> |
| 50 | + return %1 : tensor<4x!quant.uniform<i8:f32, 0.05>> |
| 51 | +} |
| 52 | + |
| 53 | +// ----- |
| 54 | + |
| 55 | +// CHECK-LABEL: @max_to_clamp_quant |
| 56 | +// CHECK: tosa.clamp %arg0 {max_fp = 3.40282347E+38 : f32, max_int = 9223372036854775807 : i64, |
| 57 | +// CHECK-SAME: min_fp = -6.000000e+00 : f32, min_int = -6 : i64} |
| 58 | +func.func @max_to_clamp_quant(%arg0: tensor<4x!quant.uniform<i8:f32, 0.05>>) -> tensor<4x!quant.uniform<i8:f32, 0.05>> { |
| 59 | + %0 = "tosa.const"() <{value = dense<-6> : tensor<1xi8>}> : () -> tensor<1x!quant.uniform<i8:f32, 0.05>> |
| 60 | + %1 = tosa.maximum %arg0, %0 : (tensor<4x!quant.uniform<i8:f32, 0.05>>, tensor<1x!quant.uniform<i8:f32, 0.05>>) -> tensor<4x!quant.uniform<i8:f32, 0.05>> |
| 61 | + return %1 : tensor<4x!quant.uniform<i8:f32, 0.05>> |
| 62 | +} |
0 commit comments