Files
clang-p2996/mlir/test/Dialect/Arith/int-range-interface.mlir
Felix Schneider acd100747f [mlir][test] Extend InferIntRangeInterface test Ops to arbitrary ints (#91850)
This PR is in preparation to some extensions to the
`InferIntRangeInterface` around the `nsw` and `nuw` flags supported in
the `arith` dialect and LLVM.

We provide some common inference logic for `index` and `arith` in
`InferIntRangeCommon.h` but our Test Ops are currently fixed to `Index`
Types. As we test the range inference for arith Ops, especially around
the overflow behaviour, it's handy to have native support for the
typical integer types in the test Ops.

This patch
1. Changes the Attributes of `test.with_bounds` ops from `Index` to
`APInt` which matches the internal representation in
`ConstantIntRanges`.
2. Allows the use of `AnyInteger` in addition to `Index` for the
operands and results of the test Ops. This now requires explicit
specification of the type in the IR, where before `Index` was implicit.
3. Requires bounds Attrs to be specified in the precision of the SSA
value, eliminating any implicit truncation or extension. (*Could this
lead to problems?*)
2024-05-14 20:33:16 +02:00

769 lines
24 KiB
MLIR

// RUN: mlir-opt -test-int-range-inference -canonicalize %s | FileCheck %s
// CHECK-LABEL: func @add_min_max
// CHECK: %[[c3:.*]] = arith.constant 3 : index
// CHECK: return %[[c3]]
func.func @add_min_max(%a: index, %b: index) -> index {
%c1 = arith.constant 1 : index
%c2 = arith.constant 2 : index
%0 = arith.minsi %a, %c1 : index
%1 = arith.maxsi %0, %c1 : index
%2 = arith.minui %b, %c2 : index
%3 = arith.maxui %2, %c2 : index
%4 = arith.addi %1, %3 : index
func.return %4 : index
}
// CHECK-LABEL: func @add_lower_bound
// CHECK: %[[sge:.*]] = arith.cmpi sge
// CHECK: return %[[sge]]
func.func @add_lower_bound(%a : i32, %b : i32) -> i1 {
%c1 = arith.constant 1 : i32
%c2 = arith.constant 2 : i32
%0 = arith.maxsi %a, %c1 : i32
%1 = arith.maxsi %b, %c1 : i32
%2 = arith.addi %0, %1 : i32
%3 = arith.cmpi sge, %2, %c2 : i32
%4 = arith.cmpi uge, %2, %c2 : i32
%5 = arith.andi %3, %4 : i1
func.return %5 : i1
}
// CHECK-LABEL: func @sub_signed_vs_unsigned
// CHECK-NOT: arith.cmpi sle
// CHECK: %[[unsigned:.*]] = arith.cmpi ule
// CHECK: return %[[unsigned]] : i1
func.func @sub_signed_vs_unsigned(%v : i64) -> i1 {
%c0 = arith.constant 0 : i64
%c2 = arith.constant 2 : i64
%c-5 = arith.constant -5 : i64
%0 = arith.minsi %v, %c2 : i64
%1 = arith.maxsi %0, %c-5 : i64
%2 = arith.subi %1, %c2 : i64
%3 = arith.cmpi sle, %2, %c0 : i64
%4 = arith.cmpi ule, %2, %c0 : i64
%5 = arith.andi %3, %4 : i1
func.return %5 : i1
}
// CHECK-LABEL: func @multiply_negatives
// CHECK: %[[false:.*]] = arith.constant false
// CHECK: return %[[false]]
func.func @multiply_negatives(%a : index, %b : index) -> i1 {
%c2 = arith.constant 2 : index
%c3 = arith.constant 3 : index
%c_1 = arith.constant -1 : index
%c_2 = arith.constant -2 : index
%c_4 = arith.constant -4 : index
%c_12 = arith.constant -12 : index
%0 = arith.maxsi %a, %c2 : index
%1 = arith.minsi %0, %c3 : index
%2 = arith.minsi %b, %c_1 : index
%3 = arith.maxsi %2, %c_4 : index
%4 = arith.muli %1, %3 : index
%5 = arith.cmpi slt, %4, %c_12 : index
%6 = arith.cmpi slt, %c_1, %4 : index
%7 = arith.ori %5, %6 : i1
func.return %7 : i1
}
// CHECK-LABEL: func @multiply_unsigned_bounds
// CHECK: %[[true:.*]] = arith.constant true
// CHECK: return %[[true]]
func.func @multiply_unsigned_bounds(%a : i16, %b : i16) -> i1 {
%c0 = arith.constant 0 : i16
%c4 = arith.constant 4 : i16
%c_mask = arith.constant 0x3fff : i16
%c_bound = arith.constant 0xfffc : i16
%0 = arith.andi %a, %c_mask : i16
%1 = arith.minui %b, %c4 : i16
%2 = arith.muli %0, %1 : i16
%3 = arith.cmpi uge, %2, %c0 : i16
%4 = arith.cmpi ule, %2, %c_bound : i16
%5 = arith.andi %3, %4 : i1
func.return %5 : i1
}
// CHECK-LABEL: @for_loop_with_increasing_arg
// CHECK: %[[ret:.*]] = arith.cmpi ule
// CHECK: return %[[ret]]
func.func @for_loop_with_increasing_arg() -> i1 {
%c0 = arith.constant 0 : index
%c1 = arith.constant 1 : index
%c4 = arith.constant 4 : index
%c16 = arith.constant 16 : index
%0 = scf.for %arg0 = %c0 to %c4 step %c1 iter_args(%arg1 = %c0) -> index {
%10 = arith.addi %arg0, %arg1 : index
scf.yield %10 : index
}
%1 = arith.cmpi ule, %0, %c16 : index
func.return %1 : i1
}
// CHECK-LABEL: @for_loop_with_constant_result
// CHECK: %[[true:.*]] = arith.constant true
// CHECK: return %[[true]]
func.func @for_loop_with_constant_result() -> i1 {
%c0 = arith.constant 0 : index
%c1 = arith.constant 1 : index
%c4 = arith.constant 4 : index
%true = arith.constant true
%0 = scf.for %arg0 = %c0 to %c4 step %c1 iter_args(%arg1 = %true) -> i1 {
%10 = arith.cmpi ule, %arg0, %c4 : index
%11 = arith.andi %10, %arg1 : i1
scf.yield %11 : i1
}
func.return %0 : i1
}
// Test to catch a bug present in some versions of the data flow analysis
// CHECK-LABEL: func @while_false
// CHECK: %[[false:.*]] = arith.constant false
// CHECK: scf.condition(%[[false]])
func.func @while_false(%arg0 : index) -> index {
%c0 = arith.constant 0 : index
%c1 = arith.constant 1 : index
%c2 = arith.constant 2 : index
%0 = arith.divui %arg0, %c2 : index
%1 = scf.while (%arg1 = %0) : (index) -> index {
%2 = arith.cmpi slt, %arg1, %c0 : index
scf.condition(%2) %arg1 : index
} do {
^bb0(%arg2 : index):
scf.yield %c2 : index
}
func.return %1 : index
}
// CHECK-LABEL: func @div_bounds_positive
// CHECK: %[[true:.*]] = arith.constant true
// CHECK: return %[[true]]
func.func @div_bounds_positive(%arg0 : index) -> i1 {
%c0 = arith.constant 0 : index
%c2 = arith.constant 2 : index
%c4 = arith.constant 4 : index
%0 = arith.maxsi %arg0, %c2 : index
%1 = arith.divsi %c4, %0 : index
%2 = arith.divui %c4, %0 : index
%3 = arith.cmpi sge, %1, %c0 : index
%4 = arith.cmpi sle, %1, %c2 : index
%5 = arith.cmpi sge, %2, %c0 : index
%6 = arith.cmpi sle, %1, %c2 : index
%7 = arith.andi %3, %4 : i1
%8 = arith.andi %7, %5 : i1
%9 = arith.andi %8, %6 : i1
func.return %9 : i1
}
// CHECK-LABEL: func @div_bounds_negative
// CHECK: %[[true:.*]] = arith.constant true
// CHECK: return %[[true]]
func.func @div_bounds_negative(%arg0 : index) -> i1 {
%c0 = arith.constant 0 : index
%c_2 = arith.constant -2 : index
%c4 = arith.constant 4 : index
%0 = arith.minsi %arg0, %c_2 : index
%1 = arith.divsi %c4, %0 : index
%2 = arith.divui %c4, %0 : index
%3 = arith.cmpi sle, %1, %c0 : index
%4 = arith.cmpi sge, %1, %c_2 : index
%5 = arith.cmpi eq, %2, %c0 : index
%7 = arith.andi %3, %4 : i1
%8 = arith.andi %7, %5 : i1
func.return %8 : i1
}
// CHECK-LABEL: func @div_zero_undefined
// CHECK: %[[ret:.*]] = arith.cmpi ule
// CHECK: return %[[ret]]
func.func @div_zero_undefined(%arg0 : index) -> i1 {
%c0 = arith.constant 0 : index
%c1 = arith.constant 1 : index
%c4 = arith.constant 4 : index
%0 = arith.andi %arg0, %c1 : index
%1 = arith.divui %c4, %0 : index
%2 = arith.cmpi ule, %1, %c4 : index
func.return %2 : i1
}
// CHECK-LABEL: func @ceil_divui
// CHECK: %[[ret:.*]] = arith.cmpi eq
// CHECK: return %[[ret]]
func.func @ceil_divui(%arg0 : index) -> i1 {
%c0 = arith.constant 0 : index
%c1 = arith.constant 1 : index
%c3 = arith.constant 3 : index
%c4 = arith.constant 4 : index
%0 = arith.minui %arg0, %c3 : index
%1 = arith.maxui %0, %c1 : index
%2 = arith.ceildivui %1, %c4 : index
%3 = arith.cmpi eq, %2, %c1 : index
%4 = arith.maxui %0, %c0 : index
%5 = arith.ceildivui %4, %c4 : index
%6 = arith.cmpi eq, %5, %c1 : index
%7 = arith.andi %3, %6 : i1
func.return %7 : i1
}
// CHECK-LABEL: func @ceil_divsi
// CHECK: %[[ret:.*]] = arith.cmpi eq
// CHECK: return %[[ret]]
func.func @ceil_divsi(%arg0 : index) -> i1 {
%c0 = arith.constant 0 : index
%c1 = arith.constant 1 : index
%c3 = arith.constant 3 : index
%c4 = arith.constant 4 : index
%c-4 = arith.constant -4 : index
%0 = arith.minsi %arg0, %c3 : index
%1 = arith.maxsi %0, %c1 : index
%2 = arith.ceildivsi %1, %c4 : index
%3 = arith.cmpi eq, %2, %c1 : index
%4 = arith.ceildivsi %1, %c-4 : index
%5 = arith.cmpi eq, %4, %c0 : index
%6 = arith.andi %3, %5 : i1
%7 = arith.maxsi %0, %c0 : index
%8 = arith.ceildivsi %7, %c4 : index
%9 = arith.cmpi eq, %8, %c1 : index
%10 = arith.andi %6, %9 : i1
func.return %10 : i1
}
// CHECK-LABEL: func @floor_divsi
// CHECK: %[[true:.*]] = arith.constant true
// CHECK: return %[[true]]
func.func @floor_divsi(%arg0 : index) -> i1 {
%c4 = arith.constant 4 : index
%c-1 = arith.constant -1 : index
%c-3 = arith.constant -3 : index
%c-4 = arith.constant -4 : index
%0 = arith.minsi %arg0, %c-1 : index
%1 = arith.maxsi %0, %c-4 : index
%2 = arith.floordivsi %1, %c4 : index
%3 = arith.cmpi eq, %2, %c-1 : index
func.return %3 : i1
}
// CHECK-LABEL: func @remui_base
// CHECK: %[[true:.*]] = arith.constant true
// CHECK: return %[[true]]
func.func @remui_base(%arg0 : index, %arg1 : index ) -> i1 {
%c2 = arith.constant 2 : index
%c4 = arith.constant 4 : index
%0 = arith.minui %arg1, %c4 : index
%1 = arith.maxui %0, %c2 : index
%2 = arith.remui %arg0, %1 : index
%3 = arith.cmpi ult, %2, %c4 : index
func.return %3 : i1
}
// CHECK-LABEL: func @remsi_base
// CHECK: %[[ret:.*]] = arith.cmpi sge
// CHECK: return %[[ret]]
func.func @remsi_base(%arg0 : index, %arg1 : index ) -> i1 {
%c0 = arith.constant 0 : index
%c2 = arith.constant 2 : index
%c4 = arith.constant 4 : index
%c-4 = arith.constant -4 : index
%true = arith.constant true
%0 = arith.minsi %arg1, %c4 : index
%1 = arith.maxsi %0, %c2 : index
%2 = arith.remsi %arg0, %1 : index
%3 = arith.cmpi sgt, %2, %c-4 : index
%4 = arith.cmpi slt, %2, %c4 : index
%5 = arith.cmpi sge, %2, %c0 : index
%6 = arith.andi %3, %4 : i1
%7 = arith.andi %5, %6 : i1
func.return %7 : i1
}
// CHECK-LABEL: func @remsi_positive
// CHECK: %[[true:.*]] = arith.constant true
// CHECK: return %[[true]]
func.func @remsi_positive(%arg0 : index, %arg1 : index ) -> i1 {
%c0 = arith.constant 0 : index
%c2 = arith.constant 2 : index
%c4 = arith.constant 4 : index
%true = arith.constant true
%0 = arith.minsi %arg1, %c4 : index
%1 = arith.maxsi %0, %c2 : index
%2 = arith.maxsi %arg0, %c0 : index
%3 = arith.remsi %2, %1 : index
%4 = arith.cmpi sge, %3, %c0 : index
%5 = arith.cmpi slt, %3, %c4 : index
%6 = arith.andi %4, %5 : i1
func.return %6 : i1
}
// CHECK-LABEL: func @remui_restricted
// CHECK: %[[true:.*]] = arith.constant true
// CHECK: return %[[true]]
func.func @remui_restricted(%arg0 : index) -> i1 {
%c2 = arith.constant 2 : index
%c3 = arith.constant 3 : index
%c4 = arith.constant 4 : index
%0 = arith.minui %arg0, %c3 : index
%1 = arith.maxui %0, %c2 : index
%2 = arith.remui %1, %c4 : index
%3 = arith.cmpi ule, %2, %c3 : index
%4 = arith.cmpi uge, %2, %c2 : index
%5 = arith.andi %3, %4 : i1
func.return %5 : i1
}
// CHECK-LABEL: func @remsi_restricted
// CHECK: %[[true:.*]] = arith.constant true
// CHECK: return %[[true]]
func.func @remsi_restricted(%arg0 : index) -> i1 {
%c2 = arith.constant 2 : index
%c3 = arith.constant 3 : index
%c-4 = arith.constant -4 : index
%0 = arith.minsi %arg0, %c3 : index
%1 = arith.maxsi %0, %c2 : index
%2 = arith.remsi %1, %c-4 : index
%3 = arith.cmpi ule, %2, %c3 : index
%4 = arith.cmpi uge, %2, %c2 : index
%5 = arith.andi %3, %4 : i1
func.return %5 : i1
}
// CHECK-LABEL: func @remui_restricted_fails
// CHECK: %[[ret:.*]] = arith.cmpi ne
// CHECK: return %[[ret]]
func.func @remui_restricted_fails(%arg0 : index) -> i1 {
%c2 = arith.constant 2 : index
%c3 = arith.constant 3 : index
%c4 = arith.constant 4 : index
%c5 = arith.constant 5 : index
%0 = arith.minui %arg0, %c5 : index
%1 = arith.maxui %0, %c3 : index
%2 = arith.remui %1, %c4 : index
%3 = arith.cmpi ne, %2, %c2 : index
func.return %3 : i1
}
// CHECK-LABEL: func @remsi_restricted_fails
// CHECK: %[[ret:.*]] = arith.cmpi ne
// CHECK: return %[[ret]]
func.func @remsi_restricted_fails(%arg0 : index) -> i1 {
%c2 = arith.constant 2 : index
%c3 = arith.constant 3 : index
%c5 = arith.constant 5 : index
%c-4 = arith.constant -4 : index
%0 = arith.minsi %arg0, %c5 : index
%1 = arith.maxsi %0, %c3 : index
%2 = arith.remsi %1, %c-4 : index
%3 = arith.cmpi ne, %2, %c2 : index
func.return %3 : i1
}
// CHECK-LABEL: func @andi
// CHECK: %[[ret:.*]] = arith.cmpi ugt
// CHECK: return %[[ret]]
func.func @andi(%arg0 : index) -> i1 {
%c2 = arith.constant 2 : index
%c5 = arith.constant 5 : index
%c7 = arith.constant 7 : index
%0 = arith.minsi %arg0, %c5 : index
%1 = arith.maxsi %0, %c2 : index
%2 = arith.andi %1, %c7 : index
%3 = arith.cmpi ugt, %2, %c5 : index
%4 = arith.cmpi ule, %2, %c7 : index
%5 = arith.andi %3, %4 : i1
func.return %5 : i1
}
// CHECK-LABEL: func @andi_doesnt_make_nonnegative
// CHECK: %[[ret:.*]] = arith.cmpi sge
// CHECK: return %[[ret]]
func.func @andi_doesnt_make_nonnegative(%arg0 : index) -> i1 {
%c0 = arith.constant 0 : index
%c1 = arith.constant 1 : index
%0 = arith.addi %arg0, %c1 : index
%1 = arith.andi %arg0, %0 : index
%2 = arith.cmpi sge, %1, %c0 : index
func.return %2 : i1
}
// CHECK-LABEL: func @ori
// CHECK: %[[true:.*]] = arith.constant true
// CHECK: return %[[true]]
func.func @ori(%arg0 : i128, %arg1 : i128) -> i1 {
%c-1 = arith.constant -1 : i128
%c0 = arith.constant 0 : i128
%0 = arith.minsi %arg1, %c-1 : i128
%1 = arith.ori %arg0, %0 : i128
%2 = arith.cmpi slt, %1, %c0 : i128
func.return %2 : i1
}
// CHECK-LABEL: func @xori
// CHECK: %[[false:.*]] = arith.constant false
// CHECK: return %[[false]]
func.func @xori(%arg0 : i64, %arg1 : i64) -> i1 {
%c0 = arith.constant 0 : i64
%c7 = arith.constant 7 : i64
%c15 = arith.constant 15 : i64
%true = arith.constant true
%0 = arith.minui %arg0, %c7 : i64
%1 = arith.minui %arg1, %c15 : i64
%2 = arith.xori %0, %1 : i64
%3 = arith.cmpi sle, %2, %c15 : i64
%4 = arith.xori %3, %true : i1
func.return %4 : i1
}
// CHECK-LABEL: func @extui
// CHECK: %[[true:.*]] = arith.constant true
// CHECK: return %[[true]]
func.func @extui(%arg0 : i16) -> i1 {
%ci16_max = arith.constant 0xffff : i32
%0 = arith.extui %arg0 : i16 to i32
%1 = arith.cmpi ule, %0, %ci16_max : i32
func.return %1 : i1
}
// CHECK-LABEL: func @extsi
// CHECK: %[[true:.*]] = arith.constant true
// CHECK: return %[[true]]
func.func @extsi(%arg0 : i16) -> i1 {
%ci16_smax = arith.constant 0x7fff : i32
%ci16_smin = arith.constant 0xffff8000 : i32
%0 = arith.extsi %arg0 : i16 to i32
%1 = arith.cmpi sle, %0, %ci16_smax : i32
%2 = arith.cmpi sge, %0, %ci16_smin : i32
%3 = arith.andi %1, %2 : i1
func.return %3 : i1
}
// CHECK-LABEL: func @trunci
// CHECK: %[[true:.*]] = arith.constant true
// CHECK: return %[[true]]
func.func @trunci(%arg0 : i32) -> i1 {
%c-14_i32 = arith.constant -14 : i32
%c-14_i16 = arith.constant -14 : i16
%ci16_smin = arith.constant 0xffff8000 : i32
%0 = arith.minsi %arg0, %c-14_i32 : i32
%1 = arith.maxsi %0, %ci16_smin : i32
%2 = arith.trunci %1 : i32 to i16
%3 = arith.cmpi sle, %2, %c-14_i16 : i16
%4 = arith.extsi %2 : i16 to i32
%5 = arith.cmpi sle, %4, %c-14_i32 : i32
%6 = arith.cmpi sge, %4, %ci16_smin : i32
%7 = arith.andi %3, %5 : i1
%8 = arith.andi %7, %6 : i1
func.return %8 : i1
}
// CHECK-LABEL: func @index_cast
// CHECK: %[[true:.*]] = arith.constant true
// CHECK: return %[[true]]
func.func @index_cast(%arg0 : index) -> i1 {
%ci32_smin = arith.constant 0xffffffff80000000 : i64
%0 = arith.index_cast %arg0 : index to i32
%1 = arith.index_cast %0 : i32 to index
%2 = arith.index_cast %ci32_smin : i64 to index
%3 = arith.cmpi sge, %1, %2 : index
func.return %3 : i1
}
// CHECK-LABEL: func @shli
// CHECK: %[[ret:.*]] = arith.cmpi sgt
// CHECK: return %[[ret]]
func.func @shli(%arg0 : i32, %arg1 : i1) -> i1 {
%c2 = arith.constant 2 : i32
%c4 = arith.constant 4 : i32
%c8 = arith.constant 8 : i32
%c32 = arith.constant 32 : i32
%c-1 = arith.constant -1 : i32
%c-16 = arith.constant -16 : i32
%0 = arith.maxsi %arg0, %c-1 : i32
%1 = arith.minsi %0, %c2 : i32
%2 = arith.select %arg1, %c2, %c4 : i32
%3 = arith.shli %1, %2 : i32
%4 = arith.cmpi sge, %3, %c-16 : i32
%5 = arith.cmpi sle, %3, %c32 : i32
%6 = arith.cmpi sgt, %3, %c8 : i32
%7 = arith.andi %4, %5 : i1
%8 = arith.andi %7, %6 : i1
func.return %8 : i1
}
// CHECK-LABEL: func @shrui
// CHECK: %[[ret:.*]] = arith.cmpi uge
// CHECK: return %[[ret]]
func.func @shrui(%arg0 : i1) -> i1 {
%c2 = arith.constant 2 : i32
%c4 = arith.constant 4 : i32
%c8 = arith.constant 8 : i32
%c32 = arith.constant 32 : i32
%0 = arith.select %arg0, %c2, %c4 : i32
%1 = arith.shrui %c32, %0 : i32
%2 = arith.cmpi ule, %1, %c8 : i32
%3 = arith.cmpi uge, %1, %c2 : i32
%4 = arith.cmpi uge, %1, %c8 : i32
%5 = arith.andi %2, %3 : i1
%6 = arith.andi %5, %4 : i1
func.return %6 : i1
}
// CHECK-LABEL: func @shrsi
// CHECK: %[[ret:.*]] = arith.cmpi slt
// CHECK: return %[[ret]]
func.func @shrsi(%arg0 : i32, %arg1 : i1) -> i1 {
%c2 = arith.constant 2 : i32
%c4 = arith.constant 4 : i32
%c8 = arith.constant 8 : i32
%c32 = arith.constant 32 : i32
%c-8 = arith.constant -8 : i32
%c-32 = arith.constant -32 : i32
%0 = arith.maxsi %arg0, %c-32 : i32
%1 = arith.minsi %0, %c32 : i32
%2 = arith.select %arg1, %c2, %c4 : i32
%3 = arith.shrsi %1, %2 : i32
%4 = arith.cmpi sge, %3, %c-8 : i32
%5 = arith.cmpi sle, %3, %c8 : i32
%6 = arith.cmpi slt, %3, %c2 : i32
%7 = arith.andi %4, %5 : i1
%8 = arith.andi %7, %6 : i1
func.return %8 : i1
}
// CHECK-LABEL: func @no_aggressive_eq
// CHECK: %[[ret:.*]] = arith.cmpi eq
// CHECK: return %[[ret]]
func.func @no_aggressive_eq(%arg0 : index) -> i1 {
%c1 = arith.constant 1 : index
%0 = arith.andi %arg0, %c1 : index
%1 = arith.minui %arg0, %c1 : index
%2 = arith.cmpi eq, %0, %1 : index
func.return %2 : i1
}
// CHECK-LABEL: func @select_union
// CHECK: %[[ret:.*]] = arith.cmpi ne
// CHECK: return %[[ret]]
func.func @select_union(%arg0 : index, %arg1 : i1) -> i1 {
%c64 = arith.constant 64 : index
%c100 = arith.constant 100 : index
%c128 = arith.constant 128 : index
%c192 = arith.constant 192 : index
%0 = arith.remui %arg0, %c64 : index
%1 = arith.addi %0, %c128 : index
%2 = arith.select %arg1, %0, %1 : index
%3 = arith.cmpi slt, %2, %c192 : index
%4 = arith.cmpi ne, %c100, %2 : index
%5 = arith.andi %3, %4 : i1
func.return %5 : i1
}
// CHECK-LABEL: func @if_union
// CHECK: %[[true:.*]] = arith.constant true
// CHECK: return %[[true]]
func.func @if_union(%arg0 : index, %arg1 : i1) -> i1 {
%c4 = arith.constant 4 : index
%c16 = arith.constant 16 : index
%c-1 = arith.constant -1 : index
%c-4 = arith.constant -4 : index
%0 = arith.minui %arg0, %c4 : index
%1 = scf.if %arg1 -> index {
%10 = arith.muli %0, %0 : index
scf.yield %10 : index
} else {
%20 = arith.muli %0, %c-1 : index
scf.yield %20 : index
}
%2 = arith.cmpi sle, %1, %c16 : index
%3 = arith.cmpi sge, %1, %c-4 : index
%4 = arith.andi %2, %3 : i1
func.return %4 : i1
}
// CHECK-LABEL: func @branch_union
// CHECK: %[[true:.*]] = arith.constant true
// CHECK: return %[[true]]
func.func @branch_union(%arg0 : index, %arg1 : i1) -> i1 {
%c4 = arith.constant 4 : index
%c16 = arith.constant 16 : index
%c-1 = arith.constant -1 : index
%c-4 = arith.constant -4 : index
%0 = arith.minui %arg0, %c4 : index
cf.cond_br %arg1, ^bb1, ^bb2
^bb1 :
%1 = arith.muli %0, %0 : index
cf.br ^bb3(%1 : index)
^bb2 :
%2 = arith.muli %0, %c-1 : index
cf.br ^bb3(%2 : index)
^bb3(%3 : index) :
%4 = arith.cmpi sle, %3, %c16 : index
%5 = arith.cmpi sge, %3, %c-4 : index
%6 = arith.andi %4, %5 : i1
func.return %6 : i1
}
// CHECK-LABEL: func @loop_bound_not_inferred_with_branch
// CHECK-DAG: %[[min:.*]] = arith.cmpi sge
// CHECK-DAG: %[[max:.*]] = arith.cmpi slt
// CHECK-DAG: %[[ret:.*]] = arith.andi %[[min]], %[[max]]
// CHECK: return %[[ret]]
func.func @loop_bound_not_inferred_with_branch(%arg0 : index, %arg1 : i1) -> i1 {
%c0 = arith.constant 0 : index
%c1 = arith.constant 1 : index
%c4 = arith.constant 4 : index
%0 = arith.minui %arg0, %c4 : index
cf.br ^bb2(%c0 : index)
^bb1(%1 : index) :
%2 = arith.addi %1, %c1 : index
cf.br ^bb2(%2 : index)
^bb2(%3 : index):
%4 = arith.cmpi ult, %3, %c4 : index
cf.cond_br %4, ^bb1(%3 : index), ^bb3(%3 : index)
^bb3(%5 : index) :
%6 = arith.cmpi sge, %5, %c0 : index
%7 = arith.cmpi slt, %5, %c4 : index
%8 = arith.andi %6, %7 : i1
func.return %8 : i1
}
// Test fon a bug where the noive implementation of trunctation led to the cast
// value being set to [0, 0].
// CHECK-LABEL: func.func @truncation_spillover
// CHECK: %[[unreplaced:.*]] = arith.index_cast
// CHECK: memref.store %[[unreplaced]]
func.func @truncation_spillover(%arg0 : memref<?xi32>) -> index {
%c0 = arith.constant 0 : index
%c1 = arith.constant 1 : index
%c2 = arith.constant 2 : index
%c49 = arith.constant 49 : index
%0 = scf.for %arg1 = %c0 to %c2 step %c1 iter_args(%arg2 = %c0) -> index {
%1 = arith.divsi %arg2, %c49 : index
%2 = arith.index_cast %1 : index to i32
memref.store %2, %arg0[%c0] : memref<?xi32>
%3 = arith.addi %arg2, %arg1 : index
scf.yield %3 : index
}
func.return %0 : index
}
// CHECK-LABEL: func.func @trunc_catches_overflow
// CHECK: %[[sge:.*]] = arith.cmpi sge
// CHECK: return %[[sge]]
func.func @trunc_catches_overflow(%arg0 : i16) -> i1 {
%c0_i16 = arith.constant 0 : i16
%c130_i16 = arith.constant 130 : i16
%c0_i8 = arith.constant 0 : i8
%0 = arith.maxui %arg0, %c0_i16 : i16
%1 = arith.minui %0, %c130_i16 : i16
%2 = arith.trunci %1 : i16 to i8
%3 = arith.cmpi sge, %2, %c0_i8 : i8
%4 = arith.cmpi uge, %2, %c0_i8 : i8
%5 = arith.andi %3, %4 : i1
func.return %5 : i1
}
// CHECK-LABEL: func.func @trunc_respects_same_high_half
// CHECK: %[[false:.*]] = arith.constant false
// CHECK: return %[[false]]
func.func @trunc_respects_same_high_half(%arg0 : i16) -> i1 {
%c256_i16 = arith.constant 256 : i16
%c257_i16 = arith.constant 257 : i16
%c2_i8 = arith.constant 2 : i8
%0 = arith.maxui %arg0, %c256_i16 : i16
%1 = arith.minui %0, %c257_i16 : i16
%2 = arith.trunci %1 : i16 to i8
%3 = arith.cmpi sge, %2, %c2_i8 : i8
func.return %3 : i1
}
// CHECK-LABEL: func.func @trunc_handles_small_signed_ranges
// CHECK: %[[true:.*]] = arith.constant true
// CHECK: return %[[true]]
func.func @trunc_handles_small_signed_ranges(%arg0 : i16) -> i1 {
%c-2_i16 = arith.constant -2 : i16
%c2_i16 = arith.constant 2 : i16
%c-2_i8 = arith.constant -2 : i8
%c2_i8 = arith.constant 2 : i8
%0 = arith.maxsi %arg0, %c-2_i16 : i16
%1 = arith.minsi %0, %c2_i16 : i16
%2 = arith.trunci %1 : i16 to i8
%3 = arith.cmpi sge, %2, %c-2_i8 : i8
%4 = arith.cmpi sle, %2, %c2_i8 : i8
%5 = arith.andi %3, %4 : i1
func.return %5 : i1
}
/// Catch a bug that crept in during an earlier refactoring that made unsigned
/// extension use the signed ranges
// CHECK-LABEL: func.func @extui_uses_unsigned
// CHECK: %[[true:.*]] = arith.constant true
// CHECK: return %[[true]]
func.func @extui_uses_unsigned(%arg0 : i32) -> i1 {
%ci32_smin = arith.constant 0x80000000 : i32
%ci32_smin_64 = arith.constant 0x80000000 : i64
%c0_i64 = arith.constant 0 : i64
%0 = arith.minui %arg0, %ci32_smin : i32
%1 = arith.extui %0 : i32 to i64
%2 = arith.cmpi sge, %1, %c0_i64 : i64
%3 = arith.cmpi ule, %1, %ci32_smin_64 : i64
%4 = arith.andi %2, %3 : i1
func.return %4 : i1
}
/// Catch a bug that caused a crash in getLoopBoundFromFold when
/// SparseConstantPropagation is loaded in the solver.
// CHECK-LABEL: func.func @caller(
// CHECK-SAME: %[[VAL_0:.*]]: memref<?xindex, 4>) {
// CHECK: call @callee(%[[VAL_0]]) : (memref<?xindex, 4>) -> ()
// CHECK: return
// CHECK: }
func.func @caller(%arg0: memref<?xindex, 4>) {
call @callee(%arg0) : (memref<?xindex, 4>) -> ()
return
}
// CHECK-LABEL: func.func private @callee(
// CHECK-SAME: %[[VAL_0:.*]]: memref<?xindex, 4>) {
// CHECK: return
// CHECK: }
func.func private @callee(%arg0: memref<?xindex, 4>) {
%c1 = arith.constant 1 : index
%c0 = arith.constant 0 : index
%0 = affine.load %arg0[0] : memref<?xindex, 4>
scf.for %arg1 = %c0 to %0 step %c1 {
}
return
}
// CHECK-LABEL: func @test_i8_bounds
// CHECK: test.reflect_bounds {smax = 127 : i8, smin = -128 : i8, umax = -1 : i8, umin = 0 : i8}
func.func @test_i8_bounds() -> i8 {
%cst1 = arith.constant 1 : i8
%0 = test.with_bounds { umin = 0 : i8, umax = 255 : i8, smin = -128 : i8, smax = 127 : i8 } : i8
%1 = arith.addi %0, %cst1 : i8
%2 = test.reflect_bounds %1 : i8
return %2: i8
}