Skip to content

Commit 3a3732c

Browse files
authored
[mlir][arith] wide integer emulation support for fpto*i ops (#132375)
Adding wide integer emulation support for `arith.fpto*i` operations. As the other emulated operations, the upper and lower `N` bits of the `i2N` integer result are emitted separately. For the unsigned case we use the following emulation ```c // example is 64 -> 32 bit emulation, but the implementation is generalized to any 2N -> N case const double TWO_POW_N = (uint_64_t(1) << N); // 2^N, N is the bitwidth of the widest int supported // f is a floating-point value representing the input of the fptoui op. uint32_t hi = (uint32_t)(f / TWO_POW_N); // Truncates the division result uint32_t lo = (uint32_t)(f - hi * TWO_POW_N); // Subtracts to get the lower bits. ``` For the signed case, we defer the emulation of the absolute value to `fptoui` and handle the sign: ``` fptosi(fp) = sign(fp) * fptoui(abs(fp)) ``` The edge cases of `NaNs, +-inf` and overflows/underflows are undefined behaviour and the resulting numbers are the combination of the lower bitwidth UB values. These operations also propagate poison values. Signed-off-by: Ege Beysel <[email protected]>
1 parent cd6e959 commit 3a3732c

File tree

4 files changed

+387
-1
lines changed

4 files changed

+387
-1
lines changed

mlir/lib/Dialect/Arith/Transforms/EmulateWideInt.cpp

Lines changed: 125 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "mlir/IR/BuiltinTypes.h"
1818
#include "mlir/IR/TypeUtilities.h"
1919
#include "mlir/Transforms/DialectConversion.h"
20+
#include "llvm/ADT/APFloat.h"
2021
#include "llvm/ADT/APInt.h"
2122
#include "llvm/Support/FormatVariadic.h"
2223
#include "llvm/Support/MathExtras.h"
@@ -1008,6 +1009,128 @@ struct ConvertUIToFP final : OpConversionPattern<arith::UIToFPOp> {
10081009
}
10091010
};
10101011

1012+
//===----------------------------------------------------------------------===//
1013+
// ConvertFPToSI
1014+
//===----------------------------------------------------------------------===//
1015+
1016+
struct ConvertFPToSI final : OpConversionPattern<arith::FPToSIOp> {
1017+
using OpConversionPattern::OpConversionPattern;
1018+
1019+
LogicalResult
1020+
matchAndRewrite(arith::FPToSIOp op, OpAdaptor adaptor,
1021+
ConversionPatternRewriter &rewriter) const override {
1022+
Location loc = op.getLoc();
1023+
// Get the input float type.
1024+
Value inFp = adaptor.getIn();
1025+
Type fpTy = inFp.getType();
1026+
1027+
Type intTy = op.getType();
1028+
1029+
auto newTy = getTypeConverter()->convertType<VectorType>(intTy);
1030+
if (!newTy)
1031+
return rewriter.notifyMatchFailure(
1032+
loc, llvm::formatv("unsupported type: {}", intTy));
1033+
1034+
// Work on the absolute value and then convert the result to signed integer.
1035+
// Defer absolute value to fptoui. If minSInt < fp < maxSInt, i.e. if the fp
1036+
// is representable in signed i2N, emits the correct result. Else, the
1037+
// result is UB.
1038+
1039+
TypedAttr zeroAttr = rewriter.getZeroAttr(fpTy);
1040+
Value zeroCst = rewriter.create<arith::ConstantOp>(loc, zeroAttr);
1041+
Value zeroCstInt = createScalarOrSplatConstant(rewriter, loc, intTy, 0);
1042+
1043+
// Get the absolute value. One could have used math.absf here, but that
1044+
// introduces an extra dependency.
1045+
Value isNeg = rewriter.create<arith::CmpFOp>(loc, arith::CmpFPredicate::OLT,
1046+
inFp, zeroCst);
1047+
Value negInFp = rewriter.create<arith::NegFOp>(loc, inFp);
1048+
1049+
Value absVal = rewriter.create<arith::SelectOp>(loc, isNeg, negInFp, inFp);
1050+
1051+
// Defer the absolute value to fptoui.
1052+
Value res = rewriter.create<arith::FPToUIOp>(loc, intTy, absVal);
1053+
1054+
// Negate the value if < 0 .
1055+
Value neg = rewriter.create<arith::SubIOp>(loc, zeroCstInt, res);
1056+
1057+
rewriter.replaceOpWithNewOp<arith::SelectOp>(op, isNeg, neg, res);
1058+
return success();
1059+
}
1060+
};
1061+
1062+
//===----------------------------------------------------------------------===//
1063+
// ConvertFPToUI
1064+
//===----------------------------------------------------------------------===//
1065+
1066+
struct ConvertFPToUI final : OpConversionPattern<arith::FPToUIOp> {
1067+
using OpConversionPattern::OpConversionPattern;
1068+
1069+
LogicalResult
1070+
matchAndRewrite(arith::FPToUIOp op, OpAdaptor adaptor,
1071+
ConversionPatternRewriter &rewriter) const override {
1072+
Location loc = op.getLoc();
1073+
// Get the input float type.
1074+
Value inFp = adaptor.getIn();
1075+
Type fpTy = inFp.getType();
1076+
1077+
Type intTy = op.getType();
1078+
auto newTy = getTypeConverter()->convertType<VectorType>(intTy);
1079+
if (!newTy)
1080+
return rewriter.notifyMatchFailure(
1081+
loc, llvm::formatv("unsupported type: {}", intTy));
1082+
unsigned newBitWidth = newTy.getElementTypeBitWidth();
1083+
1084+
Type newHalfType = IntegerType::get(inFp.getContext(), newBitWidth);
1085+
if (auto vecType = dyn_cast<VectorType>(fpTy))
1086+
newHalfType = VectorType::get(vecType.getShape(), newHalfType);
1087+
1088+
// The resulting integer has the upper part and the lower part. This would
1089+
// be interpreted as 2^N * high + low, where N is the bitwidth. Therefore,
1090+
// to calculate the higher part, we emit resHigh = fptoui(fp/2^N). For the
1091+
// lower part, we emit fptoui(fp - resHigh * 2^N). The special cases of
1092+
// overflows including +-inf, NaNs and negative numbers are UB.
1093+
1094+
const llvm::fltSemantics &fSemantics =
1095+
cast<FloatType>(getElementTypeOrSelf(fpTy)).getFloatSemantics();
1096+
1097+
auto powBitwidth = llvm::APFloat(fSemantics);
1098+
// If the integer does not fit the floating point number, we set the
1099+
// powBitwidth to inf. This ensures that the upper part is set
1100+
// correctly to 0. The opStatus inexact here only occurs when we have an
1101+
// overflow, since the number is always a power of two.
1102+
if (powBitwidth.convertFromAPInt(APInt(newBitWidth * 2, 1).shl(newBitWidth),
1103+
false, llvm::RoundingMode::TowardZero) ==
1104+
llvm::detail::opStatus::opInexact)
1105+
powBitwidth = llvm::APFloat::getInf(fSemantics);
1106+
1107+
TypedAttr powBitwidthAttr =
1108+
FloatAttr::get(getElementTypeOrSelf(fpTy), powBitwidth);
1109+
if (auto vecType = dyn_cast<VectorType>(fpTy))
1110+
powBitwidthAttr = SplatElementsAttr::get(vecType, powBitwidthAttr);
1111+
Value powBitwidthFloatCst =
1112+
rewriter.create<arith::ConstantOp>(loc, powBitwidthAttr);
1113+
1114+
Value fpDivPowBitwidth =
1115+
rewriter.create<arith::DivFOp>(loc, inFp, powBitwidthFloatCst);
1116+
Value resHigh =
1117+
rewriter.create<arith::FPToUIOp>(loc, newHalfType, fpDivPowBitwidth);
1118+
// Calculate fp - resHigh * 2^N by getting the remainder of the division
1119+
Value remainder =
1120+
rewriter.create<arith::RemFOp>(loc, inFp, powBitwidthFloatCst);
1121+
Value resLow =
1122+
rewriter.create<arith::FPToUIOp>(loc, newHalfType, remainder);
1123+
1124+
Value high = appendX1Dim(rewriter, loc, resHigh);
1125+
Value low = appendX1Dim(rewriter, loc, resLow);
1126+
1127+
Value resultVec = constructResultVector(rewriter, loc, newTy, {low, high});
1128+
1129+
rewriter.replaceOp(op, resultVec);
1130+
return success();
1131+
}
1132+
};
1133+
10111134
//===----------------------------------------------------------------------===//
10121135
// ConvertTruncI
10131136
//===----------------------------------------------------------------------===//
@@ -1184,5 +1307,6 @@ void arith::populateArithWideIntEmulationPatterns(
11841307
ConvertIndexCastIntToIndex<arith::IndexCastUIOp>,
11851308
ConvertIndexCastIndexToInt<arith::IndexCastOp, arith::ExtSIOp>,
11861309
ConvertIndexCastIndexToInt<arith::IndexCastUIOp, arith::ExtUIOp>,
1187-
ConvertSIToFP, ConvertUIToFP>(typeConverter, patterns.getContext());
1310+
ConvertSIToFP, ConvertUIToFP, ConvertFPToUI, ConvertFPToSI>(
1311+
typeConverter, patterns.getContext());
11881312
}

mlir/test/Dialect/Arith/emulate-wide-int.mlir

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,3 +1046,112 @@ func.func @sitofp_i64_f64_vector(%a : vector<3xi64>) -> vector<3xf64> {
10461046
%r = arith.sitofp %a : vector<3xi64> to vector<3xf64>
10471047
return %r : vector<3xf64>
10481048
}
1049+
1050+
// CHECK-LABEL: func @fptoui_i64_f64
1051+
// CHECK-SAME: ([[ARG:%.+]]: f64) -> vector<2xi32>
1052+
// CHECK-NEXT: [[POW:%.+]] = arith.constant 0x41F0000000000000 : f64
1053+
// CHECK-NEXT: [[DIV:%.+]] = arith.divf [[ARG]], [[POW]] : f64
1054+
// CHECK-NEXT: [[HIGHHALF:%.+]] = arith.fptoui [[DIV]] : f64 to i32
1055+
// CHECK-NEXT: [[REM:%.+]] = arith.remf [[ARG]], [[POW]] : f64
1056+
// CHECK-NEXT: [[LOWHALF:%.+]] = arith.fptoui [[REM]] : f64 to i32
1057+
// CHECK: %{{.+}} = vector.insert [[LOWHALF]], %{{.+}} [0]
1058+
// CHECK-NEXT: [[RESVEC:%.+]] = vector.insert [[HIGHHALF]], %{{.+}} [1]
1059+
// CHECK: return [[RESVEC]] : vector<2xi32>
1060+
func.func @fptoui_i64_f64(%a : f64) -> i64 {
1061+
%r = arith.fptoui %a : f64 to i64
1062+
return %r : i64
1063+
}
1064+
1065+
// CHECK-LABEL: func @fptoui_i64_f64_vector
1066+
// CHECK-SAME: ([[ARG:%.+]]: vector<3xf64>) -> vector<3x2xi32>
1067+
// CHECK-NEXT: [[POW:%.+]] = arith.constant dense<0x41F0000000000000> : vector<3xf64>
1068+
// CHECK-NEXT: [[DIV:%.+]] = arith.divf [[ARG]], [[POW]] : vector<3xf64>
1069+
// CHECK-NEXT: [[HIGHHALF:%.+]] = arith.fptoui [[DIV]] : vector<3xf64> to vector<3xi32>
1070+
// CHECK-NEXT: [[REM:%.+]] = arith.remf [[ARG]], [[POW]] : vector<3xf64>
1071+
// CHECK-NEXT: [[LOWHALF:%.+]] = arith.fptoui [[REM]] : vector<3xf64> to vector<3xi32>
1072+
// CHECK-DAG: [[HIGHHALFX1:%.+]] = vector.shape_cast [[HIGHHALF]] : vector<3xi32> to vector<3x1xi32>
1073+
// CHECK-DAG: [[LOWHALFX1:%.+]] = vector.shape_cast [[LOWHALF]] : vector<3xi32> to vector<3x1xi32>
1074+
// CHECK: %{{.+}} = vector.insert_strided_slice [[LOWHALFX1]], %{{.+}} {offsets = [0, 0], strides = [1, 1]}
1075+
// CHECK-NEXT: [[RESVEC:%.+]] = vector.insert_strided_slice [[HIGHHALFX1]], %{{.+}} {offsets = [0, 1], strides = [1, 1]}
1076+
// CHECK: return [[RESVEC]] : vector<3x2xi32>
1077+
func.func @fptoui_i64_f64_vector(%a : vector<3xf64>) -> vector<3xi64> {
1078+
%r = arith.fptoui %a : vector<3xf64> to vector<3xi64>
1079+
return %r : vector<3xi64>
1080+
}
1081+
1082+
// This generates lines that are already verified by other patterns.
1083+
// We do not re-verify these and just check for the wrapper around fptoui by following its low part.
1084+
// CHECK-LABEL: func @fptosi_i64_f64
1085+
// CHECK-SAME: ([[ARG:%.+]]: f64) -> vector<2xi32>
1086+
// CHECK: [[ZEROCST:%.+]] = arith.constant 0.000000e+00 : f64
1087+
// CHECK: [[ZEROCSTINT:%.+]] = arith.constant dense<0> : vector<2xi32>
1088+
// CHECK-NEXT: [[ISNEGATIVE:%.+]] = arith.cmpf olt, [[ARG]], [[ZEROCST]] : f64
1089+
// CHECK-NEXT: [[NEGATED:%.+]] = arith.negf [[ARG]] : f64
1090+
// CHECK-NEXT: [[ABSVALUE:%.+]] = arith.select [[ISNEGATIVE]], [[NEGATED]], [[ARG]] : f64
1091+
// CHECK-NEXT: [[POW:%.+]] = arith.constant 0x41F0000000000000 : f64
1092+
// CHECK-NEXT: [[DIV:%.+]] = arith.divf [[ABSVALUE]], [[POW]] : f64
1093+
// CHECK-NEXT: [[HIGHHALF:%.+]] = arith.fptoui [[DIV]] : f64 to i32
1094+
// CHECK-NEXT: [[REM:%.+]] = arith.remf [[ABSVALUE]], [[POW]] : f64
1095+
// CHECK-NEXT: [[LOWHALF:%.+]] = arith.fptoui [[REM]] : f64 to i32
1096+
// CHECK: vector.insert [[LOWHALF]], %{{.+}} [0] : i32 into vector<2xi32>
1097+
// CHECK-NEXT: [[FPTOUIRESVEC:%.+]] = vector.insert [[HIGHHALF]]
1098+
// CHECK: [[ZEROCSTINTHALF:%.+]] = vector.extract [[ZEROCSTINT]][0] : i32 from vector<2xi32>
1099+
// CHECK: [[SUB:%.+]] = arith.subi [[ZEROCSTINTHALF]], %{{.+}} : i32
1100+
// CHECK-NEXT: arith.cmpi ult, [[ZEROCSTINTHALF]], %{{.+}} : i32
1101+
// CHECK-NEXT: arith.extui
1102+
// CHECK-NEXT: arith.subi
1103+
// CHECK-NEXT: arith.subi
1104+
// CHECK: vector.insert [[SUB]]
1105+
// CHECK: [[SUBVEC:%.+]] = vector.insert
1106+
// CHECK: [[SUB:%.+]] = vector.extract [[SUBVEC]][0] : i32 from vector<2xi32>
1107+
// CHECK: [[LOWRES:%.+]] = vector.extract [[FPTOUIRESVEC]][0] : i32 from vector<2xi32>
1108+
// CHECK: [[ABSRES:%.+]] = arith.select [[ISNEGATIVE]], [[SUB]], [[LOWRES]] : i32
1109+
// CHECK-NEXT: arith.select [[ISNEGATIVE]]
1110+
// CHECK: vector.insert [[ABSRES]]
1111+
// CHECK-NEXT: [[ABSRESVEC:%.+]] = vector.insert
1112+
// CHECK-NEXT: return [[ABSRESVEC]] : vector<2xi32>
1113+
func.func @fptosi_i64_f64(%a : f64) -> i64 {
1114+
%r = arith.fptosi %a : f64 to i64
1115+
return %r : i64
1116+
}
1117+
1118+
// Same as the non-vector one, we don't re-verify.
1119+
// CHECK-LABEL: func @fptosi_i64_f64_vector
1120+
// CHECK-SAME: ([[ARG:%.+]]: vector<3xf64>) -> vector<3x2xi32>
1121+
// CHECK-NEXT: [[ZEROCST:%.+]] = arith.constant dense<0.000000e+00> : vector<3xf64>
1122+
// CHECK-NEXT: [[ZEROCSTINT:%.+]] = arith.constant dense<0> : vector<3x2xi32>
1123+
// CHECK-NEXT: [[ISNEGATIVE:%.+]] = arith.cmpf olt, [[ARG]], [[ZEROCST]] : vector<3xf64>
1124+
// CHECK-NEXT: [[NEGATED:%.+]] = arith.negf [[ARG]] : vector<3xf64>
1125+
// CHECK-NEXT: [[ABSVALUE:%.+]] = arith.select [[ISNEGATIVE]], [[NEGATED]], [[ARG]] : vector<3xi1>, vector<3xf64>
1126+
// CHECK-NEXT: [[POW:%.+]] = arith.constant dense<0x41F0000000000000> : vector<3xf64>
1127+
// CHECK-NEXT: [[DIV:%.+]] = arith.divf [[ABSVALUE]], [[POW]] : vector<3xf64>
1128+
// CHECK-NEXT: [[HIGHHALF:%.+]] = arith.fptoui [[DIV]] : vector<3xf64> to vector<3xi32>
1129+
// CHECK-NEXT: [[REM:%.+]] = arith.remf [[ABSVALUE]], [[POW]] : vector<3xf64>
1130+
// CHECK-NEXT: [[LOWHALF:%.+]] = arith.fptoui [[REM]] : vector<3xf64> to vector<3xi32>
1131+
// CHECK-NEXT: [[HIGHHALFX1:%.+]] = vector.shape_cast [[HIGHHALF]] : vector<3xi32> to vector<3x1xi32>
1132+
// CHECK-NEXT: [[LOWHALFX1:%.+]] = vector.shape_cast [[LOWHALF]] : vector<3xi32> to vector<3x1xi32>
1133+
// CHECK: vector.insert_strided_slice [[LOWHALFX1]], %{{.+}} {offsets = [0, 0], strides = [1, 1]} : vector<3x1xi32> into vector<3x2xi32>
1134+
// CHECK-NEXT: [[FPTOUIRESVEC:%.+]] = vector.insert_strided_slice [[HIGHHALFX1]]
1135+
// CHECK: [[ZEROCSTINTHALF:%.+]] = vector.extract_strided_slice [[ZEROCSTINT]]
1136+
// CHECK-SAME: {offsets = [0, 0], sizes = [3, 1], strides = [1, 1]} : vector<3x2xi32> to vector<3x1xi32>
1137+
// CHECK: [[SUB:%.+]] = arith.subi [[ZEROCSTINTHALF]], %{{.+}} : vector<3x1xi32>
1138+
// CHECK-NEXT: arith.cmpi ult, [[ZEROCSTINTHALF]], %{{.+}} : vector<3x1xi32>
1139+
// CHECK-NEXT: arith.extui
1140+
// CHECK-NEXT: arith.subi
1141+
// CHECK-NEXT: arith.subi
1142+
// CHECK: vector.insert_strided_slice [[SUB]]
1143+
// CHECK-NEXT: [[SUBVEC:%.+]] = vector.insert_strided_slice
1144+
// CHECK: [[SUB:%.+]] = vector.extract_strided_slice [[SUBVEC]]
1145+
// CHECK-SAME: {offsets = [0, 0], sizes = [3, 1], strides = [1, 1]} : vector<3x2xi32> to vector<3x1xi32>
1146+
// CHECK: [[LOWRES:%.+]] = vector.extract_strided_slice [[FPTOUIRESVEC]]
1147+
// CHECK-SAME: {offsets = [0, 0], sizes = [3, 1], strides = [1, 1]} : vector<3x2xi32> to vector<3x1xi32>
1148+
// CHECK: [[ISNEGATIVEX1:%.+]] = vector.shape_cast [[ISNEGATIVE]] : vector<3xi1> to vector<3x1xi1>
1149+
// CHECK: [[ABSRES:%.+]] = arith.select [[ISNEGATIVEX1]], [[SUB]], [[LOWRES]] : vector<3x1xi1>, vector<3x1xi32>
1150+
// CHECK-NEXT: arith.select [[ISNEGATIVEX1]]
1151+
// CHECK: vector.insert_strided_slice [[ABSRES]]
1152+
// CHECK-NEXT: [[ABSRESVEC:%.+]] = vector.insert_strided_slice
1153+
// CHECK-NEXT: return [[ABSRESVEC]] : vector<3x2xi32>
1154+
func.func @fptosi_i64_f64_vector(%a : vector<3xf64>) -> vector<3xi64> {
1155+
%r = arith.fptosi %a : vector<3xf64> to vector<3xi64>
1156+
return %r : vector<3xi64>
1157+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// Check that the wide integer `arith.fptosi` emulation produces the same result as wide
2+
// `arith.fptosi`. Emulate i64 ops with i32 ops.
3+
4+
// RUN: mlir-opt %s --convert-scf-to-cf --convert-cf-to-llvm --convert-vector-to-llvm \
5+
// RUN: --convert-func-to-llvm --convert-arith-to-llvm | \
6+
// RUN: mlir-runner -e entry -entry-point-result=void \
7+
// RUN: --shared-libs=%mlir_c_runner_utils | \
8+
// RUN: FileCheck %s --match-full-lines
9+
10+
// RUN: mlir-opt %s --test-arith-emulate-wide-int="widest-int-supported=32" \
11+
// RUN: --convert-scf-to-cf --convert-cf-to-llvm --convert-vector-to-llvm \
12+
// RUN: --convert-func-to-llvm --convert-arith-to-llvm | \
13+
// RUN: mlir-runner -e entry -entry-point-result=void \
14+
// RUN: --shared-libs=%mlir_c_runner_utils | \
15+
// RUN: FileCheck %s --match-full-lines
16+
17+
// Ops in this function *only* will be emulated using i32 types.
18+
func.func @emulate_fptosi(%arg: f64) -> i64 {
19+
%res = arith.fptosi %arg : f64 to i64
20+
return %res : i64
21+
}
22+
23+
func.func @check_fptosi(%arg : f64) -> () {
24+
%res = func.call @emulate_fptosi(%arg) : (f64) -> (i64)
25+
vector.print %res : i64
26+
return
27+
}
28+
29+
func.func @entry() {
30+
%cst0 = arith.constant 0.0 : f64
31+
%cst_nzero = arith.constant 0x8000000000000000 : f64
32+
%cst1 = arith.constant 1.0 : f64
33+
%cst_n1 = arith.constant -1.0 : f64
34+
%cst_n1_5 = arith.constant -1.5 : f64
35+
36+
%cstpow20 = arith.constant 1048576.0 : f64
37+
%cstnpow20 = arith.constant -1048576.0 : f64
38+
39+
%cst_i32_max = arith.constant 4294967295.0 : f64
40+
%cst_i32_min = arith.constant -4294967296.0 : f64
41+
%cst_i32_overflow = arith.constant 4294967296.0 : f64
42+
%cst_i32_noverflow = arith.constant -4294967297.0 : f64
43+
44+
45+
%cstpow40 = arith.constant 1099511627776.0 : f64
46+
%cstnpow40 = arith.constant -1099511627776.0 : f64
47+
%cst_pow40ppow20 = arith.constant 1099512676352.0 : f64
48+
%cst_npow40ppow20 = arith.constant -1099512676352.0 : f64
49+
50+
%cst_max = arith.constant 9007199254740992.0
51+
%cst_min = arith.constant -9007199254740992.0
52+
53+
// CHECK: 0
54+
func.call @check_fptosi(%cst0) : (f64) -> ()
55+
// CHECK-NEXT: 0
56+
func.call @check_fptosi(%cst_nzero) : (f64) -> ()
57+
// CHECK-NEXT: 1
58+
func.call @check_fptosi(%cst1) : (f64) -> ()
59+
// CHECK-NEXT: -1
60+
func.call @check_fptosi(%cst_n1) : (f64) -> ()
61+
// CHECK-NEXT: -1
62+
func.call @check_fptosi(%cst_n1_5) : (f64) -> ()
63+
// CHECK-NEXT: 1048576
64+
func.call @check_fptosi(%cstpow20) : (f64) -> ()
65+
// CHECK-NEXT: -1048576
66+
func.call @check_fptosi(%cstnpow20) : (f64) -> ()
67+
// CHECK-NEXT: 4294967295
68+
func.call @check_fptosi(%cst_i32_max) : (f64) -> ()
69+
// CHECK-NEXT: -4294967296
70+
func.call @check_fptosi(%cst_i32_min) : (f64) -> ()
71+
// CHECK-NEXT: 4294967296
72+
func.call @check_fptosi(%cst_i32_overflow) : (f64) -> ()
73+
// CHECK-NEXT: -4294967297
74+
func.call @check_fptosi(%cst_i32_noverflow) : (f64) -> ()
75+
// CHECK-NEXT: 1099511627776
76+
func.call @check_fptosi(%cstpow40) : (f64) -> ()
77+
// CHECK-NEXT: -1099511627776
78+
func.call @check_fptosi(%cstnpow40) : (f64) -> ()
79+
// CHECK-NEXT: 1099512676352
80+
func.call @check_fptosi(%cst_pow40ppow20) : (f64) -> ()
81+
// CHECK-NEXT: -1099512676352
82+
func.call @check_fptosi(%cst_npow40ppow20) : (f64) -> ()
83+
// CHECK-NEXT: 9007199254740992
84+
func.call @check_fptosi(%cst_max) : (f64) -> ()
85+
// CHECK-NEXT: -9007199254740992
86+
func.call @check_fptosi(%cst_min) : (f64) -> ()
87+
88+
return
89+
}

0 commit comments

Comments
 (0)