Index: mlir/include/mlir/Dialect/Math/IR/MathOps.td =================================================================== --- mlir/include/mlir/Dialect/Math/IR/MathOps.td +++ mlir/include/mlir/Dialect/Math/IR/MathOps.td @@ -538,6 +538,7 @@ %a = math.ipowi %b, %c : i32 ``` }]; + let hasFolder = 1; } //===----------------------------------------------------------------------===// Index: mlir/lib/Dialect/Math/IR/MathOps.cpp =================================================================== --- mlir/lib/Dialect/Math/IR/MathOps.cpp +++ mlir/lib/Dialect/Math/IR/MathOps.cpp @@ -134,6 +134,56 @@ }); } +//===----------------------------------------------------------------------===// +// IPowIOp folder +//===----------------------------------------------------------------------===// + +OpFoldResult math::IPowIOp::fold(ArrayRef operands) { + return constFoldBinaryOpConditional( + operands, [](const APInt &base, const APInt &power) -> Optional { + unsigned width = base.getBitWidth(); + auto zeroValue = APInt::getZero(width); + APInt oneValue{width, 1ULL, /*isSigned=*/true}; + APInt minusOneValue{width, -1ULL, /*isSigned=*/true}; + + if (power.isZero()) + return oneValue; + + if (power.isNegative()) { + // Leave 0 raised to negative power not folded. + if (base.isZero()) + return {}; + if (base.eq(oneValue)) + return oneValue; + // If abs(base) > 1, then the result is zero. + if (base.ne(minusOneValue)) + return zeroValue; + // base == -1: + // -1: power is odd + // 1: power is even + if (power[0] == 1) + return minusOneValue; + + return oneValue; + } + + // power is positive. + APInt result = oneValue; + APInt curBase = base; + APInt curPower = power; + while (true) { + if (curPower[0] == 1) + result *= curBase; + curPower.lshrInPlace(1); + if (curPower.isZero()) + return result; + curBase *= curBase; + } + }); + + return Attribute(); +} + //===----------------------------------------------------------------------===// // LogOp folder //===----------------------------------------------------------------------===// Index: mlir/test/Dialect/Math/canonicalize_ipowi.mlir =================================================================== --- /dev/null +++ mlir/test/Dialect/Math/canonicalize_ipowi.mlir @@ -0,0 +1,810 @@ +// RUN: mlir-opt %s --split-input-file -canonicalize | FileCheck %s + +// i32 cases: + +// Test power == 0 and base == 0: +// CHECK-LABEL: @ipowi32_fold() -> i32 { +// CHECK: %[[cst:.+]] = arith.constant 1 : i32 +// CHECK: return %[[cst]] : i32 +func.func @ipowi32_fold() -> i32 { + %base = arith.constant 0 : i32 + %power = arith.constant 0 : i32 + %res = math.ipowi %base, %power : i32 + return %res : i32 +} + +// ----- + +// Test power == 0 and positive base: +// CHECK-LABEL: @ipowi32_fold() -> i32 { +// CHECK: %[[cst:.+]] = arith.constant 1 : i32 +// CHECK: return %[[cst]] : i32 +func.func @ipowi32_fold() -> i32 { + %base = arith.constant 10 : i32 + %power = arith.constant 0 : i32 + %res = math.ipowi %base, %power : i32 + return %res : i32 +} + +// ----- + +// Test power == 0 and negative base: +// CHECK-LABEL: @ipowi32_fold() -> i32 { +// CHECK: %[[cst:.+]] = arith.constant 1 : i32 +// CHECK: return %[[cst]] : i32 +func.func @ipowi32_fold() -> i32 { + %base = arith.constant -10 : i32 + %power = arith.constant 0 : i32 + %res = math.ipowi %base, %power : i32 + return %res : i32 +} + +// ----- + +// Test negative power and base == 0: +// CHECK-LABEL: @ipowi32_fold() -> i32 { +// CHECK-DAG: %[[cst0:.+]] = arith.constant 0 : i32 +// CHECK-DAG: %[[cst_m1:.+]] = arith.constant -1 : i32 +// CHECK: %[[res:.+]] = math.ipowi %[[cst0]], %[[cst_m1]] : i32 +// CHECK: return %[[res]] : i32 +func.func @ipowi32_fold() -> i32 { + %base = arith.constant 0 : i32 + %power = arith.constant -1 : i32 + %res = math.ipowi %base, %power : i32 + return %res : i32 +} + +// ----- + +// Test even negative power and base == 1: +// CHECK-LABEL: @ipowi32_fold() -> i32 { +// CHECK-DAG: %[[cst:.+]] = arith.constant 1 : i32 +// CHECK: return %[[cst]] : i32 +func.func @ipowi32_fold() -> i32 { + %base = arith.constant 1 : i32 + %power = arith.constant -10 : i32 + %res = math.ipowi %base, %power : i32 + return %res : i32 +} + +// ----- + +// Test odd negative power and base > 1: +// CHECK-LABEL: @ipowi32_fold() -> i32 { +// CHECK-DAG: %[[cst:.+]] = arith.constant 0 : i32 +// CHECK: return %[[cst]] : i32 +func.func @ipowi32_fold() -> i32 { + %base = arith.constant 2 : i32 + %power = arith.constant -1 : i32 + %res = math.ipowi %base, %power : i32 + return %res : i32 +} + +// ----- + +// Test even negative power and base == -1: +// CHECK-LABEL: @ipowi32_fold() -> i32 { +// CHECK-DAG: %[[cst:.+]] = arith.constant 1 : i32 +// CHECK: return %[[cst]] : i32 +func.func @ipowi32_fold() -> i32 { + %base = arith.constant -1 : i32 + %power = arith.constant -10 : i32 + %res = math.ipowi %base, %power : i32 + return %res : i32 +} + +// ----- + +// Test odd negative power and base == -1: +// CHECK-LABEL: @ipowi32_fold() -> i32 { +// CHECK-DAG: %[[cst:.+]] = arith.constant -1 : i32 +// CHECK: return %[[cst]] : i32 +func.func @ipowi32_fold() -> i32 { + %base = arith.constant -1 : i32 + %power = arith.constant -11 : i32 + %res = math.ipowi %base, %power : i32 + return %res : i32 +} + +// ----- + +// Test even negative power and base < -1: +// CHECK-LABEL: @ipowi32_fold() -> i32 { +// CHECK-DAG: %[[cst:.+]] = arith.constant 0 : i32 +// CHECK: return %[[cst]] : i32 +func.func @ipowi32_fold() -> i32 { + %base = arith.constant -2 : i32 + %power = arith.constant -2 : i32 + %res = math.ipowi %base, %power : i32 + return %res : i32 +} + +// ----- + +// Test odd negative power and base < -1: +// CHECK-LABEL: @ipowi32_fold() -> i32 { +// CHECK-DAG: %[[cst:.+]] = arith.constant 0 : i32 +// CHECK: return %[[cst]] : i32 +func.func @ipowi32_fold() -> i32 { + %base = arith.constant -2 : i32 + %power = arith.constant -1 : i32 + %res = math.ipowi %base, %power : i32 + return %res : i32 +} + +// ----- + +// Test odd positive power and base < 0: +// CHECK-LABEL: @ipowi32_fold() -> i32 { +// CHECK-DAG: %[[cst:.+]] = arith.constant -27 : i32 +// CHECK: return %[[cst]] : i32 +func.func @ipowi32_fold() -> i32 { + %base = arith.constant -3 : i32 + %power = arith.constant 3 : i32 + %res = math.ipowi %base, %power : i32 + return %res : i32 +} + +// ----- + +// Test even positive power and base < 0: +// CHECK-LABEL: @ipowi32_fold() -> i32 { +// CHECK-DAG: %[[cst:.+]] = arith.constant 81 : i32 +// CHECK: return %[[cst]] : i32 +func.func @ipowi32_fold() -> i32 { + %base = arith.constant -3 : i32 + %power = arith.constant 4 : i32 + %res = math.ipowi %base, %power : i32 + return %res : i32 +} + +// ----- + +// Test 2 ^ 30: +// CHECK-LABEL: @ipowi32_fold() -> i32 { +// CHECK-DAG: %[[cst:.+]] = arith.constant 1073741824 : i32 +// CHECK: return %[[cst]] : i32 +func.func @ipowi32_fold() -> i32 { + %base = arith.constant 2 : i32 + %power = arith.constant 30 : i32 + %res = math.ipowi %base, %power : i32 + return %res : i32 +} + +// ----- + +// Test 2 ^ 31 (overflows int32_t): +// CHECK-LABEL: @ipowi32_fold() -> i32 { +// CHECK-DAG: %[[cst:.+]] = arith.constant -2147483648 : i32 +// CHECK: return %[[cst]] : i32 +func.func @ipowi32_fold() -> i32 { + %base = arith.constant 2 : i32 + %power = arith.constant 31 : i32 + %res = math.ipowi %base, %power : i32 + return %res : i32 +} + +// ----- + +// Test 2 ^ 32 (overflows int32_t): +// CHECK-LABEL: @ipowi32_fold() -> i32 { +// CHECK-DAG: %[[cst:.+]] = arith.constant 0 : i32 +// CHECK: return %[[cst]] : i32 +func.func @ipowi32_fold() -> i32 { + %base = arith.constant 2 : i32 + %power = arith.constant 32 : i32 + %res = math.ipowi %base, %power : i32 + return %res : i32 +} + +// ----- + +// Test vector folding: +// CHECK-LABEL: @ipowi32_fold() -> vector<2x2xi32> { +// CHECK-DAG: %[[cst:.+]] = arith.constant dense<1073741824> : vector<2x2xi32> +// CHECK: return %[[cst]] : vector<2x2xi32> +func.func @ipowi32_fold() -> vector<2x2xi32> { + %base = arith.constant 2 : i32 + %base_vec = vector.splat %base : vector<2x2xi32> + %power = arith.constant 30 : i32 + %power_vec = vector.splat %power : vector<2x2xi32> + %res = math.ipowi %base_vec, %power_vec : vector<2x2xi32> + return %res : vector<2x2xi32> +} + +// ----- + +// i64 cases: + +// Test power == 0 and base == 0: +// CHECK-LABEL: @ipowi64_fold() -> i64 { +// CHECK: %[[cst:.+]] = arith.constant 1 : i64 +// CHECK: return %[[cst]] : i64 +func.func @ipowi64_fold() -> i64 { + %base = arith.constant 0 : i64 + %power = arith.constant 0 : i64 + %res = math.ipowi %base, %power : i64 + return %res : i64 +} + +// ----- + +// Test power == 0 and positive base: +// CHECK-LABEL: @ipowi64_fold() -> i64 { +// CHECK: %[[cst:.+]] = arith.constant 1 : i64 +// CHECK: return %[[cst]] : i64 +func.func @ipowi64_fold() -> i64 { + %base = arith.constant 10 : i64 + %power = arith.constant 0 : i64 + %res = math.ipowi %base, %power : i64 + return %res : i64 +} + +// ----- + +// Test power == 0 and negative base: +// CHECK-LABEL: @ipowi64_fold() -> i64 { +// CHECK: %[[cst:.+]] = arith.constant 1 : i64 +// CHECK: return %[[cst]] : i64 +func.func @ipowi64_fold() -> i64 { + %base = arith.constant -10 : i64 + %power = arith.constant 0 : i64 + %res = math.ipowi %base, %power : i64 + return %res : i64 +} + +// ----- + +// Test negative power and base == 0: +// CHECK-LABEL: @ipowi64_fold() -> i64 { +// CHECK-DAG: %[[cst0:.+]] = arith.constant 0 : i64 +// CHECK-DAG: %[[cst_m1:.+]] = arith.constant -1 : i64 +// CHECK: %[[res:.+]] = math.ipowi %[[cst0]], %[[cst_m1]] : i64 +// CHECK: return %[[res]] : i64 +func.func @ipowi64_fold() -> i64 { + %base = arith.constant 0 : i64 + %power = arith.constant -1 : i64 + %res = math.ipowi %base, %power : i64 + return %res : i64 +} + +// ----- + +// Test even negative power and base == 1: +// CHECK-LABEL: @ipowi64_fold() -> i64 { +// CHECK-DAG: %[[cst:.+]] = arith.constant 1 : i64 +// CHECK: return %[[cst]] : i64 +func.func @ipowi64_fold() -> i64 { + %base = arith.constant 1 : i64 + %power = arith.constant -10 : i64 + %res = math.ipowi %base, %power : i64 + return %res : i64 +} + +// ----- + +// Test odd negative power and base > 1: +// CHECK-LABEL: @ipowi64_fold() -> i64 { +// CHECK-DAG: %[[cst:.+]] = arith.constant 0 : i64 +// CHECK: return %[[cst]] : i64 +func.func @ipowi64_fold() -> i64 { + %base = arith.constant 2 : i64 + %power = arith.constant -1 : i64 + %res = math.ipowi %base, %power : i64 + return %res : i64 +} + +// ----- + +// Test even negative power and base == -1: +// CHECK-LABEL: @ipowi64_fold() -> i64 { +// CHECK-DAG: %[[cst:.+]] = arith.constant 1 : i64 +// CHECK: return %[[cst]] : i64 +func.func @ipowi64_fold() -> i64 { + %base = arith.constant -1 : i64 + %power = arith.constant -10 : i64 + %res = math.ipowi %base, %power : i64 + return %res : i64 +} + +// ----- + +// Test odd negative power and base == -1: +// CHECK-LABEL: @ipowi64_fold() -> i64 { +// CHECK-DAG: %[[cst:.+]] = arith.constant -1 : i64 +// CHECK: return %[[cst]] : i64 +func.func @ipowi64_fold() -> i64 { + %base = arith.constant -1 : i64 + %power = arith.constant -11 : i64 + %res = math.ipowi %base, %power : i64 + return %res : i64 +} + +// ----- + +// Test even negative power and base < -1: +// CHECK-LABEL: @ipowi64_fold() -> i64 { +// CHECK-DAG: %[[cst:.+]] = arith.constant 0 : i64 +// CHECK: return %[[cst]] : i64 +func.func @ipowi64_fold() -> i64 { + %base = arith.constant -2 : i64 + %power = arith.constant -2 : i64 + %res = math.ipowi %base, %power : i64 + return %res : i64 +} + +// ----- + +// Test odd negative power and base < -1: +// CHECK-LABEL: @ipowi64_fold() -> i64 { +// CHECK-DAG: %[[cst:.+]] = arith.constant 0 : i64 +// CHECK: return %[[cst]] : i64 +func.func @ipowi64_fold() -> i64 { + %base = arith.constant -2 : i64 + %power = arith.constant -1 : i64 + %res = math.ipowi %base, %power : i64 + return %res : i64 +} + +// ----- + +// Test odd positive power and base < 0: +// CHECK-LABEL: @ipowi64_fold() -> i64 { +// CHECK-DAG: %[[cst:.+]] = arith.constant -27 : i64 +// CHECK: return %[[cst]] : i64 +func.func @ipowi64_fold() -> i64 { + %base = arith.constant -3 : i64 + %power = arith.constant 3 : i64 + %res = math.ipowi %base, %power : i64 + return %res : i64 +} + +// ----- + +// Test even positive power and base < 0: +// CHECK-LABEL: @ipowi64_fold() -> i64 { +// CHECK-DAG: %[[cst:.+]] = arith.constant 81 : i64 +// CHECK: return %[[cst]] : i64 +func.func @ipowi64_fold() -> i64 { + %base = arith.constant -3 : i64 + %power = arith.constant 4 : i64 + %res = math.ipowi %base, %power : i64 + return %res : i64 +} + +// ----- + +// Test 2 ^ 48: +// CHECK-LABEL: @ipowi64_fold() -> i64 { +// CHECK-DAG: %[[cst:.+]] = arith.constant 281474976710656 : i64 +// CHECK: return %[[cst]] : i64 +func.func @ipowi64_fold() -> i64 { + %base = arith.constant 2 : i64 + %power = arith.constant 48 : i64 + %res = math.ipowi %base, %power : i64 + return %res : i64 +} + +// ----- + +// Test 2 ^ 63 (overflows int64_t): +// CHECK-LABEL: @ipowi64_fold() -> i64 { +// CHECK-DAG: %[[cst:.+]] = arith.constant -9223372036854775808 : i64 +// CHECK: return %[[cst]] : i64 +func.func @ipowi64_fold() -> i64 { + %base = arith.constant 2 : i64 + %power = arith.constant 63 : i64 + %res = math.ipowi %base, %power : i64 + return %res : i64 +} + +// ----- + +// Test 2 ^ 64 (overflows int64_t): +// CHECK-LABEL: @ipowi64_fold() -> i64 { +// CHECK-DAG: %[[cst:.+]] = arith.constant 0 : i64 +// CHECK: return %[[cst]] : i64 +func.func @ipowi64_fold() -> i64 { + %base = arith.constant 2 : i64 + %power = arith.constant 64 : i64 + %res = math.ipowi %base, %power : i64 + return %res : i64 +} + +// ----- + +// i16 cases: + +// Test power == 0 and base == 0: +// CHECK-LABEL: @ipowi16_fold() -> i16 { +// CHECK: %[[cst:.+]] = arith.constant 1 : i16 +// CHECK: return %[[cst]] : i16 +func.func @ipowi16_fold() -> i16 { + %base = arith.constant 0 : i16 + %power = arith.constant 0 : i16 + %res = math.ipowi %base, %power : i16 + return %res : i16 +} + +// ----- + +// Test power == 0 and positive base: +// CHECK-LABEL: @ipowi16_fold() -> i16 { +// CHECK: %[[cst:.+]] = arith.constant 1 : i16 +// CHECK: return %[[cst]] : i16 +func.func @ipowi16_fold() -> i16 { + %base = arith.constant 10 : i16 + %power = arith.constant 0 : i16 + %res = math.ipowi %base, %power : i16 + return %res : i16 +} + +// ----- + +// Test power == 0 and negative base: +// CHECK-LABEL: @ipowi16_fold() -> i16 { +// CHECK: %[[cst:.+]] = arith.constant 1 : i16 +// CHECK: return %[[cst]] : i16 +func.func @ipowi16_fold() -> i16 { + %base = arith.constant -10 : i16 + %power = arith.constant 0 : i16 + %res = math.ipowi %base, %power : i16 + return %res : i16 +} + +// ----- + +// Test negative power and base == 0: +// CHECK-LABEL: @ipowi16_fold() -> i16 { +// CHECK-DAG: %[[cst0:.+]] = arith.constant 0 : i16 +// CHECK-DAG: %[[cst_m1:.+]] = arith.constant -1 : i16 +// CHECK: %[[res:.+]] = math.ipowi %[[cst0]], %[[cst_m1]] : i16 +// CHECK: return %[[res]] : i16 +func.func @ipowi16_fold() -> i16 { + %base = arith.constant 0 : i16 + %power = arith.constant -1 : i16 + %res = math.ipowi %base, %power : i16 + return %res : i16 +} + +// ----- + +// Test even negative power and base == 1: +// CHECK-LABEL: @ipowi16_fold() -> i16 { +// CHECK-DAG: %[[cst:.+]] = arith.constant 1 : i16 +// CHECK: return %[[cst]] : i16 +func.func @ipowi16_fold() -> i16 { + %base = arith.constant 1 : i16 + %power = arith.constant -10 : i16 + %res = math.ipowi %base, %power : i16 + return %res : i16 +} + +// ----- + +// Test odd negative power and base > 1: +// CHECK-LABEL: @ipowi16_fold() -> i16 { +// CHECK-DAG: %[[cst:.+]] = arith.constant 0 : i16 +// CHECK: return %[[cst]] : i16 +func.func @ipowi16_fold() -> i16 { + %base = arith.constant 2 : i16 + %power = arith.constant -1 : i16 + %res = math.ipowi %base, %power : i16 + return %res : i16 +} + +// ----- + +// Test even negative power and base == -1: +// CHECK-LABEL: @ipowi16_fold() -> i16 { +// CHECK-DAG: %[[cst:.+]] = arith.constant 1 : i16 +// CHECK: return %[[cst]] : i16 +func.func @ipowi16_fold() -> i16 { + %base = arith.constant -1 : i16 + %power = arith.constant -10 : i16 + %res = math.ipowi %base, %power : i16 + return %res : i16 +} + +// ----- + +// Test odd negative power and base == -1: +// CHECK-LABEL: @ipowi16_fold() -> i16 { +// CHECK-DAG: %[[cst:.+]] = arith.constant -1 : i16 +// CHECK: return %[[cst]] : i16 +func.func @ipowi16_fold() -> i16 { + %base = arith.constant -1 : i16 + %power = arith.constant -11 : i16 + %res = math.ipowi %base, %power : i16 + return %res : i16 +} + +// ----- + +// Test even negative power and base < -1: +// CHECK-LABEL: @ipowi16_fold() -> i16 { +// CHECK-DAG: %[[cst:.+]] = arith.constant 0 : i16 +// CHECK: return %[[cst]] : i16 +func.func @ipowi16_fold() -> i16 { + %base = arith.constant -2 : i16 + %power = arith.constant -2 : i16 + %res = math.ipowi %base, %power : i16 + return %res : i16 +} + +// ----- + +// Test odd negative power and base < -1: +// CHECK-LABEL: @ipowi16_fold() -> i16 { +// CHECK-DAG: %[[cst:.+]] = arith.constant 0 : i16 +// CHECK: return %[[cst]] : i16 +func.func @ipowi16_fold() -> i16 { + %base = arith.constant -2 : i16 + %power = arith.constant -1 : i16 + %res = math.ipowi %base, %power : i16 + return %res : i16 +} + +// ----- + +// Test odd positive power and base < 0: +// CHECK-LABEL: @ipowi16_fold() -> i16 { +// CHECK-DAG: %[[cst:.+]] = arith.constant -27 : i16 +// CHECK: return %[[cst]] : i16 +func.func @ipowi16_fold() -> i16 { + %base = arith.constant -3 : i16 + %power = arith.constant 3 : i16 + %res = math.ipowi %base, %power : i16 + return %res : i16 +} + +// ----- + +// Test even positive power and base < 0: +// CHECK-LABEL: @ipowi16_fold() -> i16 { +// CHECK-DAG: %[[cst:.+]] = arith.constant 81 : i16 +// CHECK: return %[[cst]] : i16 +func.func @ipowi16_fold() -> i16 { + %base = arith.constant -3 : i16 + %power = arith.constant 4 : i16 + %res = math.ipowi %base, %power : i16 + return %res : i16 +} + +// ----- + +// Test 2 ^ 14: +// CHECK-LABEL: @ipowi16_fold() -> i16 { +// CHECK-DAG: %[[cst:.+]] = arith.constant 16384 : i16 +// CHECK: return %[[cst]] : i16 +func.func @ipowi16_fold() -> i16 { + %base = arith.constant 2 : i16 + %power = arith.constant 14 : i16 + %res = math.ipowi %base, %power : i16 + return %res : i16 +} + +// ----- + +// Test 2 ^ 15 (overflows int16_t): +// CHECK-LABEL: @ipowi16_fold() -> i16 { +// CHECK-DAG: %[[cst:.+]] = arith.constant -32768 : i16 +// CHECK: return %[[cst]] : i16 +func.func @ipowi16_fold() -> i16 { + %base = arith.constant 2 : i16 + %power = arith.constant 15 : i16 + %res = math.ipowi %base, %power : i16 + return %res : i16 +} + +// ----- + +// Test 2 ^ 16 (overflows int16_t): +// CHECK-LABEL: @ipowi16_fold() -> i16 { +// CHECK-DAG: %[[cst:.+]] = arith.constant 0 : i16 +// CHECK: return %[[cst]] : i16 +func.func @ipowi16_fold() -> i16 { + %base = arith.constant 2 : i16 + %power = arith.constant 16 : i16 + %res = math.ipowi %base, %power : i16 + return %res : i16 +} + +// ----- + +// i8 cases: + +// Test power == 0 and base == 0: +// CHECK-LABEL: @ipowi8_fold() -> i8 { +// CHECK: %[[cst:.+]] = arith.constant 1 : i8 +// CHECK: return %[[cst]] : i8 +func.func @ipowi8_fold() -> i8 { + %base = arith.constant 0 : i8 + %power = arith.constant 0 : i8 + %res = math.ipowi %base, %power : i8 + return %res : i8 +} + +// ----- + +// Test power == 0 and positive base: +// CHECK-LABEL: @ipowi8_fold() -> i8 { +// CHECK: %[[cst:.+]] = arith.constant 1 : i8 +// CHECK: return %[[cst]] : i8 +func.func @ipowi8_fold() -> i8 { + %base = arith.constant 10 : i8 + %power = arith.constant 0 : i8 + %res = math.ipowi %base, %power : i8 + return %res : i8 +} + +// ----- + +// Test power == 0 and negative base: +// CHECK-LABEL: @ipowi8_fold() -> i8 { +// CHECK: %[[cst:.+]] = arith.constant 1 : i8 +// CHECK: return %[[cst]] : i8 +func.func @ipowi8_fold() -> i8 { + %base = arith.constant -10 : i8 + %power = arith.constant 0 : i8 + %res = math.ipowi %base, %power : i8 + return %res : i8 +} + +// ----- + +// Test negative power and base == 0: +// CHECK-LABEL: @ipowi8_fold() -> i8 { +// CHECK-DAG: %[[cst0:.+]] = arith.constant 0 : i8 +// CHECK-DAG: %[[cst_m1:.+]] = arith.constant -1 : i8 +// CHECK: %[[res:.+]] = math.ipowi %[[cst0]], %[[cst_m1]] : i8 +// CHECK: return %[[res]] : i8 +func.func @ipowi8_fold() -> i8 { + %base = arith.constant 0 : i8 + %power = arith.constant -1 : i8 + %res = math.ipowi %base, %power : i8 + return %res : i8 +} + +// ----- + +// Test even negative power and base == 1: +// CHECK-LABEL: @ipowi8_fold() -> i8 { +// CHECK-DAG: %[[cst:.+]] = arith.constant 1 : i8 +// CHECK: return %[[cst]] : i8 +func.func @ipowi8_fold() -> i8 { + %base = arith.constant 1 : i8 + %power = arith.constant -10 : i8 + %res = math.ipowi %base, %power : i8 + return %res : i8 +} + +// ----- + +// Test odd negative power and base > 1: +// CHECK-LABEL: @ipowi8_fold() -> i8 { +// CHECK-DAG: %[[cst:.+]] = arith.constant 0 : i8 +// CHECK: return %[[cst]] : i8 +func.func @ipowi8_fold() -> i8 { + %base = arith.constant 2 : i8 + %power = arith.constant -1 : i8 + %res = math.ipowi %base, %power : i8 + return %res : i8 +} + +// ----- + +// Test even negative power and base == -1: +// CHECK-LABEL: @ipowi8_fold() -> i8 { +// CHECK-DAG: %[[cst:.+]] = arith.constant 1 : i8 +// CHECK: return %[[cst]] : i8 +func.func @ipowi8_fold() -> i8 { + %base = arith.constant -1 : i8 + %power = arith.constant -10 : i8 + %res = math.ipowi %base, %power : i8 + return %res : i8 +} + +// ----- + +// Test odd negative power and base == -1: +// CHECK-LABEL: @ipowi8_fold() -> i8 { +// CHECK-DAG: %[[cst:.+]] = arith.constant -1 : i8 +// CHECK: return %[[cst]] : i8 +func.func @ipowi8_fold() -> i8 { + %base = arith.constant -1 : i8 + %power = arith.constant -11 : i8 + %res = math.ipowi %base, %power : i8 + return %res : i8 +} + +// ----- + +// Test even negative power and base < -1: +// CHECK-LABEL: @ipowi8_fold() -> i8 { +// CHECK-DAG: %[[cst:.+]] = arith.constant 0 : i8 +// CHECK: return %[[cst]] : i8 +func.func @ipowi8_fold() -> i8 { + %base = arith.constant -2 : i8 + %power = arith.constant -2 : i8 + %res = math.ipowi %base, %power : i8 + return %res : i8 +} + +// ----- + +// Test odd negative power and base < -1: +// CHECK-LABEL: @ipowi8_fold() -> i8 { +// CHECK-DAG: %[[cst:.+]] = arith.constant 0 : i8 +// CHECK: return %[[cst]] : i8 +func.func @ipowi8_fold() -> i8 { + %base = arith.constant -2 : i8 + %power = arith.constant -1 : i8 + %res = math.ipowi %base, %power : i8 + return %res : i8 +} + +// ----- + +// Test odd positive power and base < 0: +// CHECK-LABEL: @ipowi8_fold() -> i8 { +// CHECK-DAG: %[[cst:.+]] = arith.constant -27 : i8 +// CHECK: return %[[cst]] : i8 +func.func @ipowi8_fold() -> i8 { + %base = arith.constant -3 : i8 + %power = arith.constant 3 : i8 + %res = math.ipowi %base, %power : i8 + return %res : i8 +} + +// ----- + +// Test even positive power and base < 0: +// CHECK-LABEL: @ipowi8_fold() -> i8 { +// CHECK-DAG: %[[cst:.+]] = arith.constant 81 : i8 +// CHECK: return %[[cst]] : i8 +func.func @ipowi8_fold() -> i8 { + %base = arith.constant -3 : i8 + %power = arith.constant 4 : i8 + %res = math.ipowi %base, %power : i8 + return %res : i8 +} + +// ----- + +// Test 2 ^ 6: +// CHECK-LABEL: @ipowi8_fold() -> i8 { +// CHECK-DAG: %[[cst:.+]] = arith.constant 64 : i8 +// CHECK: return %[[cst]] : i8 +func.func @ipowi8_fold() -> i8 { + %base = arith.constant 2 : i8 + %power = arith.constant 6 : i8 + %res = math.ipowi %base, %power : i8 + return %res : i8 +} + +// ----- + +// Test 2 ^ 7 (overflows int8_t): +// CHECK-LABEL: @ipowi8_fold() -> i8 { +// CHECK-DAG: %[[cst:.+]] = arith.constant -128 : i8 +// CHECK: return %[[cst]] : i8 +func.func @ipowi8_fold() -> i8 { + %base = arith.constant 2 : i8 + %power = arith.constant 7 : i8 + %res = math.ipowi %base, %power : i8 + return %res : i8 +} + +// ----- + +// Test 2 ^ 8 (overflows int8_t): +// CHECK-LABEL: @ipowi8_fold() -> i8 { +// CHECK-DAG: %[[cst:.+]] = arith.constant 0 : i8 +// CHECK: return %[[cst]] : i8 +func.func @ipowi8_fold() -> i8 { + %base = arith.constant 2 : i8 + %power = arith.constant 8 : i8 + %res = math.ipowi %base, %power : i8 + return %res : i8 +}