AMDGPU: Refine rcp/rsq intrinsic folding for modern FP rules

We have to assume undef could be an snan, which would need quieting so
returning qnan is safer than undef. Also consider strictfp, and don't
care if the result rounded.
This commit is contained in:
Matt Arsenault 2020-05-21 21:04:06 -04:00
parent 1d96dca949
commit 27fe841aa6
2 changed files with 38 additions and 20 deletions

View File

@ -3500,17 +3500,24 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) {
Value *Src = II->getArgOperand(0);
// TODO: Move to ConstantFolding/InstSimplify?
if (isa<UndefValue>(Src))
return replaceInstUsesWith(CI, Src);
if (isa<UndefValue>(Src)) {
Type *Ty = II->getType();
auto *QNaN = ConstantFP::get(Ty, APFloat::getQNaN(Ty->getFltSemantics()));
return replaceInstUsesWith(CI, QNaN);
}
if (II->isStrictFP())
break;
if (const ConstantFP *C = dyn_cast<ConstantFP>(Src)) {
const APFloat &ArgVal = C->getValueAPF();
APFloat Val(ArgVal.getSemantics(), 1);
APFloat::opStatus Status = Val.divide(ArgVal,
APFloat::rmNearestTiesToEven);
// Only do this if it was exact and therefore not dependent on the
// rounding mode.
if (Status == APFloat::opOK)
Val.divide(ArgVal, APFloat::rmNearestTiesToEven);
// This is more precise than the instruction may give.
//
// TODO: The instruction always flushes denormal results (except for f16),
// should this also?
return replaceInstUsesWith(CI, ConstantFP::get(II->getContext(), Val));
}
@ -3520,8 +3527,12 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) {
Value *Src = II->getArgOperand(0);
// TODO: Move to ConstantFolding/InstSimplify?
if (isa<UndefValue>(Src))
return replaceInstUsesWith(CI, Src);
if (isa<UndefValue>(Src)) {
Type *Ty = II->getType();
auto *QNaN = ConstantFP::get(Ty, APFloat::getQNaN(Ty->getFltSemantics()));
return replaceInstUsesWith(CI, QNaN);
}
break;
}
case Intrinsic::amdgcn_frexp_mant:

View File

@ -10,7 +10,7 @@ declare double @llvm.amdgcn.rcp.f64(double) nounwind readnone
define float @test_constant_fold_rcp_f32_undef() nounwind {
; CHECK-LABEL: @test_constant_fold_rcp_f32_undef(
; CHECK-NEXT: ret float undef
; CHECK-NEXT: ret float 0x7FF8000000000000
;
%val = call float @llvm.amdgcn.rcp.f32(float undef) nounwind readnone
ret float %val
@ -50,8 +50,7 @@ define double @test_constant_fold_rcp_f64_half() nounwind {
define float @test_constant_fold_rcp_f32_43() nounwind {
; CHECK-LABEL: @test_constant_fold_rcp_f32_43(
; CHECK-NEXT: [[VAL:%.*]] = call float @llvm.amdgcn.rcp.f32(float 4.300000e+01)
; CHECK-NEXT: ret float [[VAL]]
; CHECK-NEXT: ret float 0x3F97D05F40000000
;
%val = call float @llvm.amdgcn.rcp.f32(float 4.300000e+01) nounwind readnone
ret float %val
@ -59,13 +58,21 @@ define float @test_constant_fold_rcp_f32_43() nounwind {
define double @test_constant_fold_rcp_f64_43() nounwind {
; CHECK-LABEL: @test_constant_fold_rcp_f64_43(
; CHECK-NEXT: [[VAL:%.*]] = call double @llvm.amdgcn.rcp.f64(double 4.300000e+01)
; CHECK-NEXT: ret double [[VAL]]
; CHECK-NEXT: ret double 0x3F97D05F417D05F4
;
%val = call double @llvm.amdgcn.rcp.f64(double 4.300000e+01) nounwind readnone
ret double %val
}
define float @test_constant_fold_rcp_f32_43_strictfp() nounwind strictfp {
; CHECK-LABEL: @test_constant_fold_rcp_f32_43_strictfp(
; CHECK-NEXT: [[VAL:%.*]] = call float @llvm.amdgcn.rcp.f32(float 4.300000e+01) #7
; CHECK-NEXT: ret float [[VAL]]
;
%val = call float @llvm.amdgcn.rcp.f32(float 4.300000e+01) strictfp nounwind readnone
ret float %val
}
; --------------------------------------------------------------------
; llvm.amdgcn.rsq
; --------------------------------------------------------------------
@ -74,7 +81,7 @@ declare float @llvm.amdgcn.rsq.f32(float) nounwind readnone
define float @test_constant_fold_rsq_f32_undef() nounwind {
; CHECK-LABEL: @test_constant_fold_rsq_f32_undef(
; CHECK-NEXT: ret float undef
; CHECK-NEXT: ret float 0x7FF8000000000000
;
%val = call float @llvm.amdgcn.rsq.f32(float undef) nounwind readnone
ret float %val
@ -2387,8 +2394,8 @@ declare i32 @llvm.amdgcn.ballot.i32(i1) nounwind readnone convergent
define i64 @ballot_nocombine_64(i1 %i) {
; CHECK-LABEL: @ballot_nocombine_64(
; CHECK-NEXT: %b = call i64 @llvm.amdgcn.ballot.i64(i1 %i)
; CHECK-NEXT: ret i64 %b
; CHECK-NEXT: [[B:%.*]] = call i64 @llvm.amdgcn.ballot.i64(i1 [[I:%.*]])
; CHECK-NEXT: ret i64 [[B]]
;
%b = call i64 @llvm.amdgcn.ballot.i64(i1 %i)
ret i64 %b
@ -2413,8 +2420,8 @@ define i64 @ballot_one_64() {
define i32 @ballot_nocombine_32(i1 %i) {
; CHECK-LABEL: @ballot_nocombine_32(
; CHECK-NEXT: %b = call i32 @llvm.amdgcn.ballot.i32(i1 %i)
; CHECK-NEXT: ret i32 %b
; CHECK-NEXT: [[B:%.*]] = call i32 @llvm.amdgcn.ballot.i32(i1 [[I:%.*]])
; CHECK-NEXT: ret i32 [[B]]
;
%b = call i32 @llvm.amdgcn.ballot.i32(i1 %i)
ret i32 %b