Skip to content

Commit 68ca207

Browse files
[fircg] Lower to saturated fp to int conversions
fptosi and fptoui llvm instructions become poison during optimization when the conversion cannot be performed. The standard mandates that a real converted to an int must be converted to the largest integer that does not exceed the magnitude of the original and keeps the same sign. The saturated floating point conversions match these semantics more closely than the regular conversion instructions.
1 parent b15ccd4 commit 68ca207

File tree

3 files changed

+255
-9
lines changed

3 files changed

+255
-9
lines changed

flang/lib/Optimizer/CodeGen/CodeGen.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -835,10 +835,20 @@ struct ConvertOpConversion : public fir::FIROpConversion<fir::ConvertOp> {
835835
return mlir::success();
836836
}
837837
if (mlir::isa<mlir::IntegerType>(toTy)) {
838-
if (toTy.isUnsignedInteger())
839-
rewriter.replaceOpWithNewOp<mlir::LLVM::FPToUIOp>(convert, toTy, op0);
840-
else
841-
rewriter.replaceOpWithNewOp<mlir::LLVM::FPToSIOp>(convert, toTy, op0);
838+
// NOTE: We are checking the fir type here because toTy is an LLVM type
839+
// which is signless, and we need to use the intrinsic that matches the
840+
// sign of the output in fir.
841+
if (toFirTy.isUnsignedInteger()) {
842+
auto intrinsicName =
843+
mlir::StringAttr::get(convert.getContext(), "llvm.fptoui.sat");
844+
rewriter.replaceOpWithNewOp<mlir::LLVM::CallIntrinsicOp>(
845+
convert, toTy, intrinsicName, op0);
846+
} else {
847+
auto intrinsicName =
848+
mlir::StringAttr::get(convert.getContext(), "llvm.fptosi.sat");
849+
rewriter.replaceOpWithNewOp<mlir::LLVM::CallIntrinsicOp>(
850+
convert, toTy, intrinsicName, op0);
851+
}
842852
return mlir::success();
843853
}
844854
} else if (mlir::isa<mlir::IntegerType>(fromTy)) {

flang/test/Fir/convert-to-llvm.fir

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -711,11 +711,11 @@ func.func @convert_from_float(%arg0 : f32) {
711711
// CHECK: %{{.*}} = llvm.fpext %[[ARG0]] : f32 to f64
712712
// CHECK: %{{.*}} = llvm.fpext %[[ARG0]] : f32 to f80
713713
// CHECK: %{{.*}} = llvm.fpext %[[ARG0]] : f32 to f128
714-
// CHECK: %{{.*}} = llvm.fptosi %[[ARG0]] : f32 to i1
715-
// CHECK: %{{.*}} = llvm.fptosi %[[ARG0]] : f32 to i8
716-
// CHECK: %{{.*}} = llvm.fptosi %[[ARG0]] : f32 to i16
717-
// CHECK: %{{.*}} = llvm.fptosi %[[ARG0]] : f32 to i32
718-
// CHECK: %{{.*}} = llvm.fptosi %[[ARG0]] : f32 to i64
714+
// CHECK: %{{.*}} = llvm.call_intrinsic "llvm.fptosi.sat"(%[[ARG0]]) : (f32) -> i1
715+
// CHECK: %{{.*}} = llvm.call_intrinsic "llvm.fptosi.sat"(%[[ARG0]]) : (f32) -> i8
716+
// CHECK: %{{.*}} = llvm.call_intrinsic "llvm.fptosi.sat"(%[[ARG0]]) : (f32) -> i16
717+
// CHECK: %{{.*}} = llvm.call_intrinsic "llvm.fptosi.sat"(%[[ARG0]]) : (f32) -> i32
718+
// CHECK: %{{.*}} = llvm.call_intrinsic "llvm.fptosi.sat"(%[[ARG0]]) : (f32) -> i64
719719

720720
// -----
721721

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
! RUN: %flang -funsigned %s -o %t && %t | FileCheck %s
2+
! RUN: %flang -funsigned -emit-llvm -S -o - %s | FileCheck %s --check-prefix=LLVMIR
3+
4+
module fp_convert_m
5+
implicit none
6+
interface set_and_print
7+
module procedure set_and_print_r16
8+
module procedure set_and_print_r8
9+
end interface
10+
contains
11+
subroutine set_and_print_r16(value)
12+
real(kind=16), intent(in) :: value
13+
integer(kind=1) :: i8
14+
integer(kind=2) :: i16
15+
integer(kind=4) :: i32
16+
integer(kind=8) :: i64
17+
integer(kind=16) :: i128
18+
unsigned(kind=1) :: u8
19+
unsigned(kind=2) :: u16
20+
unsigned(kind=4) :: u32
21+
unsigned(kind=8) :: u64
22+
unsigned(kind=16) :: u128
23+
print *, "Original real(16) value:", value
24+
i8 = int(value, kind=1)
25+
i16 = int(value, kind=2)
26+
i32 = int(value, kind=4)
27+
i64 = int(value, kind=8)
28+
i128 = int(value, kind=16)
29+
u8 = uint(value, kind=1)
30+
u16 = uint(value, kind=2)
31+
u32 = uint(value, kind=4)
32+
u64 = uint(value, kind=8)
33+
u128 = uint(value, kind=16)
34+
print *, "Converted to 8-bit integer:", i8
35+
print *, "Converted to 16-bit integer:", i16
36+
print *, "Converted to 32-bit integer:", i32
37+
print *, "Converted to 64-bit integer:", i64
38+
print *, "Converted to 128-bit integer:", i128
39+
print *, "Converted to 8-bit unsigned integer:", u8
40+
print *, "Converted to 16-bit unsigned integer:", u16
41+
print *, "Converted to 32-bit unsigned integer:", u32
42+
print *, "Converted to 64-bit unsigned integer:", u64
43+
print *, "Converted to 128-bit unsigned integer:", u128
44+
end subroutine
45+
46+
subroutine set_and_print_r8(value)
47+
real(kind=8), intent(in) :: value
48+
integer(kind=1) :: i8
49+
integer(kind=2) :: i16
50+
integer(kind=4) :: i32
51+
integer(kind=8) :: i64
52+
integer(kind=16) :: i128
53+
unsigned(kind=1) :: u8
54+
unsigned(kind=2) :: u16
55+
unsigned(kind=4) :: u32
56+
unsigned(kind=8) :: u64
57+
unsigned(kind=16) :: u128
58+
print *, "Original real(8) value:", value
59+
i8 = int(value, kind=1)
60+
i16 = int(value, kind=2)
61+
i32 = int(value, kind=4)
62+
i64 = int(value, kind=8)
63+
i128 = int(value, kind=16)
64+
u8 = uint(value, kind=1)
65+
u16 = uint(value, kind=2)
66+
u32 = uint(value, kind=4)
67+
u64 = uint(value, kind=8)
68+
u128 = uint(value, kind=16)
69+
print *, "Converted to 8-bit integer:", i8
70+
print *, "Converted to 16-bit integer:", i16
71+
print *, "Converted to 32-bit integer:", i32
72+
print *, "Converted to 64-bit integer:", i64
73+
print *, "Converted to 128-bit integer:", i128
74+
print *, "Converted to 8-bit unsigned integer:", u8
75+
print *, "Converted to 16-bit unsigned integer:", u16
76+
print *, "Converted to 32-bit unsigned integer:", u32
77+
print *, "Converted to 64-bit unsigned integer:", u64
78+
print *, "Converted to 128-bit unsigned integer:", u128
79+
end subroutine
80+
end module fp_convert_m
81+
82+
program fp_convert
83+
use ieee_arithmetic, only: ieee_value, ieee_quiet_nan, ieee_positive_inf, ieee_negative_inf
84+
use fp_convert_m, only: set_and_print
85+
implicit none
86+
87+
real(kind=8) :: nan, inf, ninf
88+
nan = ieee_value(nan, ieee_quiet_nan)
89+
inf = ieee_value(inf, ieee_positive_inf)
90+
ninf = ieee_value(ninf, ieee_negative_inf)
91+
92+
call set_and_print(huge(0.0_8))
93+
call set_and_print(-huge(0.0_8))
94+
call set_and_print(huge(0.0_16))
95+
call set_and_print(-huge(0.0_16))
96+
call set_and_print(tiny(0.0_8))
97+
call set_and_print(-tiny(0.0_8))
98+
call set_and_print(tiny(0.0_16))
99+
call set_and_print(-tiny(0.0_16))
100+
call set_and_print(nan)
101+
call set_and_print(inf)
102+
call set_and_print(ninf)
103+
104+
end program fp_convert
105+
106+
! LLVMIR: call i8 @llvm.fptosi.sat.i8.f128(fp128 %{{.+}})
107+
! LLVMIR: call i16 @llvm.fptosi.sat.i16.f128(fp128 %{{.+}})
108+
! LLVMIR: call i32 @llvm.fptosi.sat.i32.f128(fp128 %{{.+}})
109+
! LLVMIR: call i64 @llvm.fptosi.sat.i64.f128(fp128 %{{.+}})
110+
! LLVMIR: call i128 @llvm.fptosi.sat.i128.f128(fp128 %{{.+}})
111+
! LLVMIR: call i8 @llvm.fptoui.sat.i8.f128(fp128 %{{.+}})
112+
! LLVMIR: call i16 @llvm.fptoui.sat.i16.f128(fp128 %{{.+}})
113+
! LLVMIR: call i32 @llvm.fptoui.sat.i32.f128(fp128 %{{.+}})
114+
! LLVMIR: call i64 @llvm.fptoui.sat.i64.f128(fp128 %{{.+}})
115+
! LLVMIR: call i128 @llvm.fptoui.sat.i128.f128(fp128 %{{.+}})
116+
! LLVMIR: call i8 @llvm.fptosi.sat.i8.f64(double %{{.+}})
117+
! LLVMIR: call i16 @llvm.fptosi.sat.i16.f64(double %{{.+}})
118+
! LLVMIR: call i32 @llvm.fptosi.sat.i32.f64(double %{{.+}})
119+
! LLVMIR: call i64 @llvm.fptosi.sat.i64.f64(double %{{.+}})
120+
! LLVMIR: call i128 @llvm.fptosi.sat.i128.f64(double %{{.+}})
121+
! LLVMIR: call i8 @llvm.fptoui.sat.i8.f64(double %{{.+}})
122+
! LLVMIR: call i16 @llvm.fptoui.sat.i16.f64(double %{{.+}})
123+
! LLVMIR: call i32 @llvm.fptoui.sat.i32.f64(double %{{.+}})
124+
! LLVMIR: call i64 @llvm.fptoui.sat.i64.f64(double %{{.+}})
125+
! LLVMIR: call i128 @llvm.fptoui.sat.i128.f64(double %{{.+}})
126+
127+
! CHECK: Converted to 8-bit integer: 127
128+
! CHECK: Converted to 16-bit integer: 32767
129+
! CHECK: Converted to 32-bit integer: 2147483647
130+
! CHECK: Converted to 64-bit integer: 9223372036854775807
131+
! CHECK: Converted to 128-bit integer: 170141183460469231731687303715884105727
132+
! CHECK: Converted to 8-bit unsigned integer: 255
133+
! CHECK: Converted to 16-bit unsigned integer: 65535
134+
! CHECK: Converted to 32-bit unsigned integer: 4294967295
135+
! CHECK: Converted to 64-bit unsigned integer: 18446744073709551615
136+
! CHECK: Converted to 128-bit unsigned integer: 340282366920938463463374607431768211455
137+
! CHECK: Converted to 8-bit integer: -128
138+
! CHECK: Converted to 16-bit integer: -32768
139+
! CHECK: Converted to 32-bit integer: -2147483648
140+
! CHECK: Converted to 64-bit integer: -9223372036854775808
141+
! CHECK: Converted to 128-bit integer: -170141183460469231731687303715884105728
142+
! CHECK: Converted to 8-bit unsigned integer: 0
143+
! CHECK: Converted to 16-bit unsigned integer: 0
144+
! CHECK: Converted to 32-bit unsigned integer: 0
145+
! CHECK: Converted to 64-bit unsigned integer: 0
146+
! CHECK: Converted to 128-bit unsigned integer: 0
147+
! CHECK: Converted to 8-bit integer: 127
148+
! CHECK: Converted to 16-bit integer: 32767
149+
! CHECK: Converted to 32-bit integer: 2147483647
150+
! CHECK: Converted to 64-bit integer: 9223372036854775807
151+
! CHECK: Converted to 128-bit integer: 170141183460469231731687303715884105727
152+
! CHECK: Converted to 8-bit unsigned integer: 255
153+
! CHECK: Converted to 16-bit unsigned integer: 65535
154+
! CHECK: Converted to 32-bit unsigned integer: 4294967295
155+
! CHECK: Converted to 64-bit unsigned integer: 18446744073709551615
156+
! CHECK: Converted to 128-bit unsigned integer: 340282366920938463463374607431768211455
157+
! CHECK: Converted to 8-bit integer: -128
158+
! CHECK: Converted to 16-bit integer: -32768
159+
! CHECK: Converted to 32-bit integer: -2147483648
160+
! CHECK: Converted to 64-bit integer: -9223372036854775808
161+
! CHECK: Converted to 128-bit integer: -170141183460469231731687303715884105728
162+
! CHECK: Converted to 8-bit unsigned integer: 0
163+
! CHECK: Converted to 16-bit unsigned integer: 0
164+
! CHECK: Converted to 32-bit unsigned integer: 0
165+
! CHECK: Converted to 64-bit unsigned integer: 0
166+
! CHECK: Converted to 128-bit unsigned integer: 0
167+
! CHECK: Converted to 8-bit integer: 0
168+
! CHECK: Converted to 16-bit integer: 0
169+
! CHECK: Converted to 32-bit integer: 0
170+
! CHECK: Converted to 64-bit integer: 0
171+
! CHECK: Converted to 128-bit integer: 0
172+
! CHECK: Converted to 8-bit unsigned integer: 0
173+
! CHECK: Converted to 16-bit unsigned integer: 0
174+
! CHECK: Converted to 32-bit unsigned integer: 0
175+
! CHECK: Converted to 64-bit unsigned integer: 0
176+
! CHECK: Converted to 128-bit unsigned integer: 0
177+
! CHECK: Converted to 8-bit integer: 0
178+
! CHECK: Converted to 16-bit integer: 0
179+
! CHECK: Converted to 32-bit integer: 0
180+
! CHECK: Converted to 64-bit integer: 0
181+
! CHECK: Converted to 128-bit integer: 0
182+
! CHECK: Converted to 8-bit unsigned integer: 0
183+
! CHECK: Converted to 16-bit unsigned integer: 0
184+
! CHECK: Converted to 32-bit unsigned integer: 0
185+
! CHECK: Converted to 64-bit unsigned integer: 0
186+
! CHECK: Converted to 128-bit unsigned integer: 0
187+
! CHECK: Converted to 8-bit integer: 0
188+
! CHECK: Converted to 16-bit integer: 0
189+
! CHECK: Converted to 32-bit integer: 0
190+
! CHECK: Converted to 64-bit integer: 0
191+
! CHECK: Converted to 128-bit integer: 0
192+
! CHECK: Converted to 8-bit unsigned integer: 0
193+
! CHECK: Converted to 16-bit unsigned integer: 0
194+
! CHECK: Converted to 32-bit unsigned integer: 0
195+
! CHECK: Converted to 64-bit unsigned integer: 0
196+
! CHECK: Converted to 128-bit unsigned integer: 0
197+
! CHECK: Converted to 8-bit integer: 0
198+
! CHECK: Converted to 16-bit integer: 0
199+
! CHECK: Converted to 32-bit integer: 0
200+
! CHECK: Converted to 64-bit integer: 0
201+
! CHECK: Converted to 128-bit integer: 0
202+
! CHECK: Converted to 8-bit unsigned integer: 0
203+
! CHECK: Converted to 16-bit unsigned integer: 0
204+
! CHECK: Converted to 32-bit unsigned integer: 0
205+
! CHECK: Converted to 64-bit unsigned integer: 0
206+
! CHECK: Converted to 128-bit unsigned integer: 0
207+
! CHECK: Converted to 8-bit integer: 0
208+
! CHECK: Converted to 16-bit integer: 0
209+
! CHECK: Converted to 32-bit integer: 0
210+
! CHECK: Converted to 64-bit integer: 0
211+
! CHECK: Converted to 128-bit integer: 0
212+
! CHECK: Converted to 8-bit unsigned integer: 0
213+
! CHECK: Converted to 16-bit unsigned integer: 0
214+
! CHECK: Converted to 32-bit unsigned integer: 0
215+
! CHECK: Converted to 64-bit unsigned integer: 0
216+
! CHECK: Converted to 128-bit unsigned integer: 0
217+
! CHECK: Converted to 8-bit integer: 127
218+
! CHECK: Converted to 16-bit integer: 32767
219+
! CHECK: Converted to 32-bit integer: 2147483647
220+
! CHECK: Converted to 64-bit integer: 9223372036854775807
221+
! CHECK: Converted to 128-bit integer: 170141183460469231731687303715884105727
222+
! CHECK: Converted to 8-bit unsigned integer: 255
223+
! CHECK: Converted to 16-bit unsigned integer: 65535
224+
! CHECK: Converted to 32-bit unsigned integer: 4294967295
225+
! CHECK: Converted to 64-bit unsigned integer: 18446744073709551615
226+
! CHECK: Converted to 128-bit unsigned integer: 340282366920938463463374607431768211455
227+
! CHECK: Converted to 8-bit integer: -128
228+
! CHECK: Converted to 16-bit integer: -32768
229+
! CHECK: Converted to 32-bit integer: -2147483648
230+
! CHECK: Converted to 64-bit integer: -9223372036854775808
231+
! CHECK: Converted to 128-bit integer: -170141183460469231731687303715884105728
232+
! CHECK: Converted to 8-bit unsigned integer: 0
233+
! CHECK: Converted to 16-bit unsigned integer: 0
234+
! CHECK: Converted to 32-bit unsigned integer: 0
235+
! CHECK: Converted to 64-bit unsigned integer: 0
236+
! CHECK: Converted to 128-bit unsigned integer: 0

0 commit comments

Comments
 (0)