758 lines
24 KiB
MLIR
758 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
|
|
}
|