From: Jeff Niu Date: Tue, 11 Oct 2022 16:47:00 +0000 (-0700) Subject: [mlir][index] Add folders for `index` ops X-Git-Tag: upstream/17.0.6~29898 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=83c3eebdec0d3028e9c7f4dfe080071b26621ec8;p=platform%2Fupstream%2Fllvm.git [mlir][index] Add folders for `index` ops This patch adds folders for `index` dialect ops. Ths folders are careful to ensure that fold results are valid on both 32-bit and 64-bit targets. Depends on D135689 Reviewed By: rriddle Differential Revision: https://reviews.llvm.org/D135694 --- diff --git a/mlir/include/mlir/Dialect/Index/IR/IndexDialect.td b/mlir/include/mlir/Dialect/Index/IR/IndexDialect.td index a0b155e..be0fea7 100644 --- a/mlir/include/mlir/Dialect/Index/IR/IndexDialect.td +++ b/mlir/include/mlir/Dialect/Index/IR/IndexDialect.td @@ -81,6 +81,7 @@ def IndexDialect : Dialect { void registerOperations(); }]; + let hasConstantMaterializer = 1; let useDefaultAttributePrinterParser = 1; } diff --git a/mlir/include/mlir/Dialect/Index/IR/IndexOps.td b/mlir/include/mlir/Dialect/Index/IR/IndexOps.td index c8dc0072..b72283a 100644 --- a/mlir/include/mlir/Dialect/Index/IR/IndexOps.td +++ b/mlir/include/mlir/Dialect/Index/IR/IndexOps.td @@ -34,6 +34,7 @@ class IndexBinaryOp traits = []> let arguments = (ins Index:$lhs, Index:$rhs); let results = (outs Index:$result); let assemblyFormat = "$lhs `,` $rhs attr-dict"; + let hasFolder = 1; } //===----------------------------------------------------------------------===// @@ -378,6 +379,7 @@ def Index_CmpOp : IndexOp<"cmp"> { let arguments = (ins IndexCmpPredicateAttr:$pred, Index:$lhs, Index:$rhs); let results = (outs I1:$result); let assemblyFormat = "`` $pred `(` $lhs `,` $rhs `)` attr-dict"; + let hasFolder = 1; } //===----------------------------------------------------------------------===// @@ -422,6 +424,7 @@ def Index_ConstantOp : IndexOp<"constant", [ConstantLike]> { let arguments = (ins IndexAttr:$value); let results = (outs Index:$result); let assemblyFormat = "attr-dict $value"; + let hasFolder = 1; let builders = [OpBuilder<(ins "int64_t":$value)>]; } @@ -449,6 +452,7 @@ def Index_BoolConstantOp : IndexOp<"bool.constant", [ConstantLike]> { let arguments = (ins BoolAttr:$value); let results = (outs I1:$result); let assemblyFormat = "attr-dict $value"; + let hasFolder = 1; } #endif // INDEX_OPS diff --git a/mlir/include/mlir/Support/LLVM.h b/mlir/include/mlir/Support/LLVM.h index bb7e5b9..e442ca5 100644 --- a/mlir/include/mlir/Support/LLVM.h +++ b/mlir/include/mlir/Support/LLVM.h @@ -99,6 +99,7 @@ namespace mlir { using llvm::cast; using llvm::cast_or_null; using llvm::dyn_cast; +using llvm::dyn_cast_if_present; using llvm::dyn_cast_or_null; using llvm::isa; using llvm::isa_and_nonnull; diff --git a/mlir/lib/Dialect/Index/IR/IndexOps.cpp b/mlir/lib/Dialect/Index/IR/IndexOps.cpp index 9c513da..fcbb076 100644 --- a/mlir/lib/Dialect/Index/IR/IndexOps.cpp +++ b/mlir/lib/Dialect/Index/IR/IndexOps.cpp @@ -26,6 +26,264 @@ void IndexDialect::registerOperations() { >(); } +Operation *IndexDialect::materializeConstant(OpBuilder &b, Attribute value, + Type type, Location loc) { + // Materialize bool constants as `i1`. + if (auto boolValue = dyn_cast(value)) { + if (!type.isSignlessInteger(1)) + return nullptr; + return b.create(loc, type, boolValue); + } + + // Materialize integer attributes as `index`. + if (auto indexValue = dyn_cast(value)) { + if (!indexValue.getType().isa() || !type.isa()) + return nullptr; + assert(indexValue.getValue().getBitWidth() == + IndexType::kInternalStorageBitWidth); + return b.create(loc, indexValue); + } + + return nullptr; +} + +//===----------------------------------------------------------------------===// +// Fold Utilities +//===----------------------------------------------------------------------===// + +/// Fold an index operation irrespective of the target bitwidth. The +/// operation must satisfy the property: +/// +/// ``` +/// trunc(f(a, b)) = f(trunc(a), trunc(b)) +/// ``` +/// +/// For all values of `a` and `b`. The function accepts a lambda that computes +/// the integer result, which in turn must satisfy the above property. +static OpFoldResult foldBinaryOpUnchecked( + ArrayRef operands, + function_ref calculate) { + assert(operands.size() == 2 && "binary operation expected 2 operands"); + auto lhs = dyn_cast_if_present(operands[0]); + auto rhs = dyn_cast_if_present(operands[1]); + if (!lhs || !rhs) + return {}; + + APInt result = calculate(lhs.getValue(), rhs.getValue()); + assert(result.trunc(32) == + calculate(lhs.getValue().trunc(32), rhs.getValue().trunc(32))); + return IntegerAttr::get(IndexType::get(lhs.getContext()), std::move(result)); +} + +/// Fold an index operation only if the truncated 64-bit result matches the +/// 32-bit result for operations that don't satisfy the above property. These +/// are operations where the upper bits of the operands can affect the lower +/// bits of the results. +/// +/// The function accepts a lambda that computes the integer result in both +/// 64-bit and 32-bit. If either call returns `None`, the operation is not +/// folded. +static OpFoldResult foldBinaryOpChecked( + ArrayRef operands, + function_ref(const APInt &, const APInt &lhs)> calculate) { + assert(operands.size() == 2 && "binary operation expected 2 operands"); + auto lhs = dyn_cast_if_present(operands[0]); + auto rhs = dyn_cast_if_present(operands[1]); + // Only fold index operands. + if (!lhs || !rhs) + return {}; + + // Compute the 64-bit result and the 32-bit result. + Optional result64 = calculate(lhs.getValue(), rhs.getValue()); + if (!result64) + return {}; + Optional result32 = + calculate(lhs.getValue().trunc(32), rhs.getValue().trunc(32)); + if (!result32) + return {}; + // Compare the truncated 64-bit result to the 32-bit result. + if (result64->trunc(32) != *result32) + return {}; + // The operation can be folded for these particular operands. + return IntegerAttr::get(IndexType::get(lhs.getContext()), + std::move(*result64)); +} + +//===----------------------------------------------------------------------===// +// AddOp +//===----------------------------------------------------------------------===// + +OpFoldResult AddOp::fold(ArrayRef operands) { + return foldBinaryOpUnchecked( + operands, [](const APInt &lhs, const APInt &rhs) { return lhs + rhs; }); +} + +//===----------------------------------------------------------------------===// +// SubOp +//===----------------------------------------------------------------------===// + +OpFoldResult SubOp::fold(ArrayRef operands) { + return foldBinaryOpUnchecked( + operands, [](const APInt &lhs, const APInt &rhs) { return lhs - rhs; }); +} + +//===----------------------------------------------------------------------===// +// MulOp +//===----------------------------------------------------------------------===// + +OpFoldResult MulOp::fold(ArrayRef operands) { + return foldBinaryOpUnchecked( + operands, [](const APInt &lhs, const APInt &rhs) { return lhs * rhs; }); +} + +//===----------------------------------------------------------------------===// +// DivSOp +//===----------------------------------------------------------------------===// + +OpFoldResult DivSOp::fold(ArrayRef operands) { + return foldBinaryOpChecked( + operands, [](const APInt &lhs, const APInt &rhs) -> Optional { + // Don't fold division by zero. + if (rhs.isZero()) + return None; + return lhs.sdiv(rhs); + }); +} + +//===----------------------------------------------------------------------===// +// DivUOp +//===----------------------------------------------------------------------===// + +OpFoldResult DivUOp::fold(ArrayRef operands) { + return foldBinaryOpChecked( + operands, [](const APInt &lhs, const APInt &rhs) -> Optional { + // Don't fold division by zero. + if (rhs.isZero()) + return None; + return lhs.udiv(rhs); + }); +} + +//===----------------------------------------------------------------------===// +// CeilDivSOp +//===----------------------------------------------------------------------===// + +/// Compute `ceildivs(n, m)` as `x = m > 0 ? -1 : 1` and then +/// `n*m > 0 ? (n+x)/m + 1 : -(-n/m)`. +static Optional calculateCeilDivS(const APInt &n, const APInt &m) { + // Don't fold division by zero. + if (m.isZero()) + return None; + // Short-circuit the zero case. + if (n.isZero()) + return n; + + bool mGtZ = m.sgt(0); + if (n.sgt(0) != mGtZ) { + // If the operands have different signs, compute the negative result. Signed + // division overflow is not possible, since if `m == -1`, `n` can be at most + // `INT_MAX`, and `-INT_MAX != INT_MIN` in two's complement. + return -(-n).sdiv(m); + } + // Otherwise, compute the positive result. Signed division overflow is not + // possible since if `m == -1`, `x` will be `1`. + int64_t x = mGtZ ? -1 : 1; + return (n + x).sdiv(m) + 1; +} + +OpFoldResult CeilDivSOp::fold(ArrayRef operands) { + return foldBinaryOpChecked(operands, calculateCeilDivS); +} + +//===----------------------------------------------------------------------===// +// CeilDivUOp +//===----------------------------------------------------------------------===// + +OpFoldResult CeilDivUOp::fold(ArrayRef operands) { + // Compute `ceildivu(n, m)` as `n == 0 ? 0 : (n-1)/m + 1`. + return foldBinaryOpChecked( + operands, [](const APInt &n, const APInt &m) -> Optional { + // Don't fold division by zero. + if (m.isZero()) + return None; + // Short-circuit the zero case. + if (n.isZero()) + return n; + + return (n - 1).udiv(m) + 1; + }); +} + +//===----------------------------------------------------------------------===// +// FloorDivSOp +//===----------------------------------------------------------------------===// + +/// Compute `floordivs(n, m)` as `x = m < 0 ? 1 : -1` and then +/// `n*m < 0 ? -1 - (x-n)/m : n/m`. +static Optional calculateFloorDivS(const APInt &n, const APInt &m) { + // Don't fold division by zero. + if (m.isZero()) + return None; + // Short-circuit the zero case. + if (n.isZero()) + return n; + + bool mLtZ = m.slt(0); + if (n.slt(0) == mLtZ) { + // If the operands have the same sign, compute the positive result. + return n.sdiv(m); + } + // If the operands have different signs, compute the negative result. Signed + // division overflow is not possible since if `m == -1`, `x` will be 1 and + // `n` can be at most `INT_MAX`. + int64_t x = mLtZ ? 1 : -1; + return -1 - (x - n).sdiv(m); +} + +OpFoldResult FloorDivSOp::fold(ArrayRef operands) { + return foldBinaryOpChecked(operands, calculateFloorDivS); +} + +//===----------------------------------------------------------------------===// +// RemSOp +//===----------------------------------------------------------------------===// + +OpFoldResult RemSOp::fold(ArrayRef operands) { + return foldBinaryOpChecked(operands, [](const APInt &lhs, const APInt &rhs) { + return lhs.srem(rhs); + }); +} + +//===----------------------------------------------------------------------===// +// RemUOp +//===----------------------------------------------------------------------===// + +OpFoldResult RemUOp::fold(ArrayRef operands) { + return foldBinaryOpChecked(operands, [](const APInt &lhs, const APInt &rhs) { + return lhs.urem(rhs); + }); +} + +//===----------------------------------------------------------------------===// +// MaxSOp +//===----------------------------------------------------------------------===// + +OpFoldResult MaxSOp::fold(ArrayRef operands) { + return foldBinaryOpChecked(operands, [](const APInt &lhs, const APInt &rhs) { + return lhs.sgt(rhs) ? lhs : rhs; + }); +} + +//===----------------------------------------------------------------------===// +// MaxUOp +//===----------------------------------------------------------------------===// + +OpFoldResult MaxUOp::fold(ArrayRef operands) { + return foldBinaryOpChecked(operands, [](const APInt &lhs, const APInt &rhs) { + return lhs.ugt(rhs) ? lhs : rhs; + }); +} + //===----------------------------------------------------------------------===// // CastSOp //===----------------------------------------------------------------------===// @@ -43,6 +301,74 @@ bool CastUOp::areCastCompatible(TypeRange lhsTypes, TypeRange rhsTypes) { } //===----------------------------------------------------------------------===// +// CmpOp +//===----------------------------------------------------------------------===// + +/// Compare two integers according to the comparison predicate. +bool compareIndices(const APInt &lhs, const APInt &rhs, + IndexCmpPredicate pred) { + switch (pred) { + case IndexCmpPredicate::EQ: + return lhs.eq(rhs); + case IndexCmpPredicate::NE: + return lhs.ne(rhs); + case IndexCmpPredicate::SGE: + return lhs.sge(rhs); + case IndexCmpPredicate::SGT: + return lhs.sgt(rhs); + case IndexCmpPredicate::SLE: + return lhs.sle(rhs); + case IndexCmpPredicate::SLT: + return lhs.slt(rhs); + case IndexCmpPredicate::UGE: + return lhs.uge(rhs); + case IndexCmpPredicate::UGT: + return lhs.ugt(rhs); + case IndexCmpPredicate::ULE: + return lhs.ule(rhs); + case IndexCmpPredicate::ULT: + return lhs.ult(rhs); + } + llvm_unreachable("unhandled IndexCmpPredicate predicate"); +} + +OpFoldResult CmpOp::fold(ArrayRef operands) { + assert(operands.size() == 2 && "compare expected 2 operands"); + auto lhs = dyn_cast_if_present(operands[0]); + auto rhs = dyn_cast_if_present(operands[1]); + if (!lhs || !rhs) + return {}; + + // Perform the comparison in 64-bit and 32-bit. + bool result64 = compareIndices(lhs.getValue(), rhs.getValue(), getPred()); + bool result32 = compareIndices(lhs.getValue().trunc(32), + rhs.getValue().trunc(32), getPred()); + if (result64 != result32) + return {}; + return BoolAttr::get(getContext(), result64); +} + +//===----------------------------------------------------------------------===// +// ConstantOp +//===----------------------------------------------------------------------===// + +OpFoldResult ConstantOp::fold(ArrayRef operands) { + return getValueAttr(); +} + +void ConstantOp::build(OpBuilder &b, OperationState &state, int64_t value) { + build(b, state, b.getIndexType(), b.getIndexAttr(value)); +} + +//===----------------------------------------------------------------------===// +// BoolConstantOp +//===----------------------------------------------------------------------===// + +OpFoldResult BoolConstantOp::fold(ArrayRef operands) { + return getValueAttr(); +} + +//===----------------------------------------------------------------------===// // ODS-Generated Definitions //===----------------------------------------------------------------------===// diff --git a/mlir/test/Dialect/Index/index-canonicalize.mlir b/mlir/test/Dialect/Index/index-canonicalize.mlir new file mode 100644 index 0000000..f9b33f8 --- /dev/null +++ b/mlir/test/Dialect/Index/index-canonicalize.mlir @@ -0,0 +1,319 @@ +// RUN: mlir-opt %s -canonicalize | FileCheck %s + +// CHECK-LABEL: @add +func.func @add() -> (index, index) { + %0 = index.constant 1 + %1 = index.constant 2100 + %2 = index.constant 3000000001 + %3 = index.constant 4000002100 + // Folds normally. + %4 = index.add %0, %1 + // Folds even though values exceed INT32_MAX. + %5 = index.add %2, %3 + + // CHECK-DAG: %[[A:.*]] = index.constant 2101 + // CHECK-DAG: %[[B:.*]] = index.constant 7000002101 + // CHECK: return %[[A]], %[[B]] + return %4, %5 : index, index +} + +// CHECK-LABEL: @add_overflow +func.func @add_overflow() -> (index, index) { + %0 = index.constant 2000000000 + %1 = index.constant 8000000000000000000 + // Folds normally. + %2 = index.add %0, %0 + // Folds and overflows. + %3 = index.add %1, %1 + + // CHECK-DAG: %[[A:.*]] = index.constant 4{{0+}} + // CHECK-DAG: %[[B:.*]] = index.constant -2446{{[0-9]+}} + // CHECK: return %[[A]], %[[B]] + return %2, %3 : index, index +} + +// CHECK-LABEL: @sub +func.func @sub() -> index { + %0 = index.constant -2000000000 + %1 = index.constant 3000000000 + %2 = index.sub %0, %1 + // CHECK: %[[A:.*]] = index.constant -5{{0+}} + // CHECK: return %[[A]] + return %2 : index +} + +// CHECK-LABEL: @mul +func.func @mul() -> index { + %0 = index.constant 8000000002000000000 + %1 = index.constant 2 + %2 = index.mul %0, %1 + // CHECK: %[[A:.*]] = index.constant -2446{{[0-9]+}} + // CHECK: return %[[A]] + return %2 : index +} + +// CHECK-LABEL: @divs +func.func @divs() -> index { + %0 = index.constant -2 + %1 = index.constant 0x200000000 + %2 = index.divs %1, %0 + // CHECK: %[[A:.*]] = index.constant -429{{[0-9]+}} + // CHECK: return %[[A]] + return %2 : index +} + +// CHECK-LABEL: @divs_nofold +func.func @divs_nofold() -> (index, index) { + %0 = index.constant 0 + %1 = index.constant 0x100000000 + %2 = index.constant 2 + + // Divide by zero. + // CHECK: index.divs + %3 = index.divs %2, %0 + // 32-bit result differs from 64-bit. + // CHECK: index.divs + %4 = index.divs %1, %2 + + return %3, %4 : index, index +} + +// CHECK-LABEL: @divu +func.func @divu() -> index { + %0 = index.constant -2 + %1 = index.constant 0x200000000 + %2 = index.divu %1, %0 + // CHECK: %[[A:.*]] = index.constant 0 + // CHECK: return %[[A]] + return %2 : index +} + +// CHECK-LABEL: @divu_nofold +func.func @divu_nofold() -> (index, index) { + %0 = index.constant 0 + %1 = index.constant 0x100000000 + %2 = index.constant 2 + + // Divide by zero. + // CHECK: index.divu + %3 = index.divu %2, %0 + // 32-bit result differs from 64-bit. + // CHECK: index.divu + %4 = index.divu %1, %2 + + return %3, %4 : index, index +} + +// CHECK-LABEL: @ceildivs +func.func @ceildivs() -> (index, index, index) { + %c0 = index.constant 0 + %c2 = index.constant 2 + %c5 = index.constant 5 + + // CHECK-DAG: %[[A:.*]] = index.constant 0 + %0 = index.ceildivs %c0, %c5 + + // CHECK-DAG: %[[B:.*]] = index.constant 1 + %1 = index.ceildivs %c2, %c5 + + // CHECK-DAG: %[[C:.*]] = index.constant 3 + %2 = index.ceildivs %c5, %c2 + + // CHECK: return %[[A]], %[[B]], %[[C]] + return %0, %1, %2 : index, index, index +} + +// CHECK-LABEL: @ceildivs_neg +func.func @ceildivs_neg() -> index { + %c5 = index.constant -5 + %c2 = index.constant 2 + // CHECK: %[[A:.*]] = index.constant -2 + %0 = index.ceildivs %c5, %c2 + // CHECK: return %[[A]] + return %0 : index +} + +// CHECK-LABEL: @ceildivs_edge +func.func @ceildivs_edge() -> (index, index) { + %cn1 = index.constant -1 + %cIntMin = index.constant -2147483648 + %cIntMax = index.constant 2147483647 + + // The result is 0 on 32-bit. + // CHECK-DAG: %[[A:.*]] = index.constant 2147483648 + %0 = index.ceildivs %cIntMin, %cn1 + + // CHECK-DAG: %[[B:.*]] = index.constant -2147483647 + %1 = index.ceildivs %cIntMax, %cn1 + + // CHECK: return %[[A]], %[[B]] + return %0, %1 : index, index +} + +// CHECK-LABEL: @ceildivu +func.func @ceildivu() -> index { + %0 = index.constant 0x200000001 + %1 = index.constant 2 + // CHECK: %[[A:.*]] = index.constant 429{{[0-9]+}}7 + %2 = index.ceildivu %0, %1 + // CHECK: return %[[A]] + return %2 : index +} + +// CHECK-LABEL: @floordivs +func.func @floordivs() -> index { + %0 = index.constant -5 + %1 = index.constant 2 + // CHECK: %[[A:.*]] = index.constant -3 + %2 = index.floordivs %0, %1 + // CHECK: return %[[A]] + return %2 : index +} + +// CHECK-LABEL: @floordivs_edge +func.func @floordivs_edge() -> (index, index) { + %cIntMin = index.constant -2147483648 + %cIntMax = index.constant 2147483647 + %n1 = index.constant -1 + %p1 = index.constant 1 + + // CHECK-DAG: %[[A:.*]] = index.constant -2147483648 + // CHECK-DAG: %[[B:.*]] = index.constant -2147483647 + %0 = index.floordivs %cIntMin, %p1 + %1 = index.floordivs %cIntMax, %n1 + + // CHECK: return %[[A]], %[[B]] + return %0, %1 : index, index +} + +// CHECK-LABEL: @floordivs_nofold +func.func @floordivs_nofold() -> index { + %lhs = index.constant 0x100000000 + %c2 = index.constant 2 + + // 32-bit result differs from 64-bit. + // CHECK: index.floordivs + %0 = index.floordivs %lhs, %c2 + + return %0 : index +} + +// CHECK-LABEL: @rems +func.func @rems() -> index { + %lhs = index.constant -5 + %rhs = index.constant 2 + // CHECK: %[[A:.*]] = index.constant -1 + %0 = index.rems %lhs, %rhs + // CHECK: return %[[A]] + return %0 : index +} + +// CHECK-LABEL: @rems_nofold +func.func @rems_nofold() -> index { + %lhs = index.constant 2 + %rhs = index.constant 0x100000001 + // 32-bit result differs from 64-bit. + // CHECK: index.rems + %0 = index.rems %lhs, %rhs + return %0 : index +} + +// CHECK-LABEL: @remu +func.func @remu() -> index { + %lhs = index.constant 2 + %rhs = index.constant -1 + // CHECK: %[[A:.*]] = index.constant 2 + %0 = index.remu %lhs, %rhs + // CHECK: return %[[A]] + return %0 : index +} + +// CHECK-LABEL: @remu_nofold +func.func @remu_nofold() -> index { + %lhs = index.constant 2 + %rhs = index.constant 0x100000001 + // 32-bit result differs from 64-bit. + // CHECK: index.remu + %0 = index.remu %lhs, %rhs + return %0 : index +} + +// CHECK-LABEL: @maxs +func.func @maxs() -> index { + %lhs = index.constant -4 + %rhs = index.constant 2 + // CHECK: %[[A:.*]] = index.constant 2 + %0 = index.maxs %lhs, %rhs + // CHECK: return %[[A]] + return %0 : index +} + +// CHECK-LABEL: @maxs_nofold +func.func @maxs_nofold() -> index { + %lhs = index.constant 1 + %rhs = index.constant 0x100000000 + // 32-bit result differs from 64-bit. + // CHECK: index.maxs + %0 = index.maxs %lhs, %rhs + return %0 : index +} + +// CHECK-LABEL: @maxs_edge +func.func @maxs_edge() -> index { + %lhs = index.constant 1 + %rhs = index.constant 0x100000001 + // Truncated 64-bit result is the same as 32-bit. + // CHECK: %[[A:.*]] = index.constant 429{{[0-9]+}} + %0 = index.maxs %lhs, %rhs + // CHECK: return %[[A]] + return %0 : index +} + +// CHECK-LABEL: @maxu +func.func @maxu() -> index { + %lhs = index.constant -1 + %rhs = index.constant 1 + // CHECK: %[[A:.*]] = index.constant -1 + %0 = index.maxu %lhs, %rhs + // CHECK: return %[[A]] + return %0 : index +} + +// CHECK-LABEL: @cmp +func.func @cmp() -> (i1, i1, i1, i1) { + %a = index.constant 0 + %b = index.constant -1 + %c = index.constant -2 + %d = index.constant 4 + + %0 = index.cmp slt(%a, %b) + %1 = index.cmp ugt(%b, %a) + %2 = index.cmp ne(%d, %a) + %3 = index.cmp sgt(%b, %a) + + // CHECK-DAG: %[[TRUE:.*]] = index.bool.constant true + // CHECK-DAG: %[[FALSE:.*]] = index.bool.constant false + // CHECK: return %[[FALSE]], %[[TRUE]], %[[TRUE]], %[[FALSE]] + return %0, %1, %2, %3 : i1, i1, i1, i1 +} + +// CHECK-LABEL: @cmp_nofold +func.func @cmp_nofold() -> i1 { + %lhs = index.constant 1 + %rhs = index.constant 0x100000000 + // 32-bit result differs from 64-bit. + // CHECK: index.cmp slt + %0 = index.cmp slt(%lhs, %rhs) + return %0 : i1 +} + +// CHECK-LABEL: @cmp_edge +func.func @cmp_edge() -> i1 { + %lhs = index.constant 1 + %rhs = index.constant 0x100000002 + // 64-bit result is the same as 32-bit. + // CHECK: %[[TRUE:.*]] = index.bool.constant true + %0 = index.cmp slt(%lhs, %rhs) + // CHECK: return %[[TRUE]] + return %0 : i1 +}