Skip to content

Commit 5146917

Browse files
[ConstantFolding] Fix incorrect nvvm_round folding (#151563)
The `nvvm_round` intrinsic should round to the nearest even number in the case of ties. It lowers to PTX `cvt.rni`, which will "round to nearest integer, choosing even integer if source is equidistant between two integers", so it matches the semantics of `rint` (and not `round` as the name suggests).
1 parent 2b27377 commit 5146917

File tree

2 files changed

+52
-3
lines changed

2 files changed

+52
-3
lines changed

llvm/lib/Analysis/ConstantFolding.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2679,11 +2679,12 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
26792679
case Intrinsic::nvvm_round_ftz_f:
26802680
case Intrinsic::nvvm_round_f:
26812681
case Intrinsic::nvvm_round_d: {
2682-
// Use APFloat implementation instead of native libm call, as some
2683-
// implementations (e.g. on PPC) do not preserve the sign of negative 0.
2682+
// nvvm_round is lowered to PTX cvt.rni, which will round to nearest
2683+
// integer, choosing even integer if source is equidistant between two
2684+
// integers, so the semantics are closer to "rint" rather than "round".
26842685
bool IsFTZ = nvvm::UnaryMathIntrinsicShouldFTZ(IntrinsicID);
26852686
auto V = IsFTZ ? FTZPreserveSign(APF) : APF;
2686-
V.roundToIntegral(APFloat::rmNearestTiesToAway);
2687+
V.roundToIntegral(APFloat::rmNearestTiesToEven);
26872688
return ConstantFP::get(Ty->getContext(), V);
26882689
}
26892690

llvm/test/Transforms/InstSimplify/const-fold-nvvm-unary-arithmetic.ll

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,54 @@ define float @test_round_ftz_f_neg_1_5() {
416416
ret float %res
417417
}
418418

419+
define double @test_round_d_2_5() {
420+
; CHECK-LABEL: define double @test_round_d_2_5() {
421+
; CHECK-NEXT: ret double 2.000000e+00
422+
;
423+
%res = call double @llvm.nvvm.round.d(double 2.5)
424+
ret double %res
425+
}
426+
427+
define float @test_round_f_2_5() {
428+
; CHECK-LABEL: define float @test_round_f_2_5() {
429+
; CHECK-NEXT: ret float 2.000000e+00
430+
;
431+
%res = call float @llvm.nvvm.round.f(float 2.5)
432+
ret float %res
433+
}
434+
435+
define float @test_round_ftz_f_2_5() {
436+
; CHECK-LABEL: define float @test_round_ftz_f_2_5() {
437+
; CHECK-NEXT: ret float 2.000000e+00
438+
;
439+
%res = call float @llvm.nvvm.round.ftz.f(float 2.5)
440+
ret float %res
441+
}
442+
443+
define double @test_round_d_neg_2_5() {
444+
; CHECK-LABEL: define double @test_round_d_neg_2_5() {
445+
; CHECK-NEXT: ret double -2.000000e+00
446+
;
447+
%res = call double @llvm.nvvm.round.d(double -2.5)
448+
ret double %res
449+
}
450+
451+
define float @test_round_f_neg_2_5() {
452+
; CHECK-LABEL: define float @test_round_f_neg_2_5() {
453+
; CHECK-NEXT: ret float -2.000000e+00
454+
;
455+
%res = call float @llvm.nvvm.round.f(float -2.5)
456+
ret float %res
457+
}
458+
459+
define float @test_round_ftz_f_neg_2_5() {
460+
; CHECK-LABEL: define float @test_round_ftz_f_neg_2_5() {
461+
; CHECK-NEXT: ret float -2.000000e+00
462+
;
463+
%res = call float @llvm.nvvm.round.ftz.f(float -2.5)
464+
ret float %res
465+
}
466+
419467
define double @test_round_d_neg_subnorm() {
420468
; CHECK-LABEL: define double @test_round_d_neg_subnorm() {
421469
; CHECK-NEXT: ret double -0.000000e+00

0 commit comments

Comments
 (0)