diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -3397,9 +3397,6 @@ /// NOTE: Do not check 'nsz' here because that fast-math-flag does not guarantee /// that a value is not -0.0. It only guarantees that -0.0 may be treated /// the same as +0.0 in floating-point ops. -/// -/// NOTE: this function will need to be revisited when we support non-default -/// rounding modes! bool llvm::CannotBeNegativeZero(const Value *V, const TargetLibraryInfo *TLI, unsigned Depth) { if (auto *CFP = dyn_cast(V)) @@ -3429,9 +3426,21 @@ case Intrinsic::sqrt: case Intrinsic::canonicalize: return CannotBeNegativeZero(Call->getArgOperand(0), TLI, Depth + 1); + case Intrinsic::experimental_constrained_sqrt: { + // NOTE: This rounding mode restriction may be too strict. + const auto *CI = cast(Call); + if (CI->getRoundingMode() == RoundingMode::NearestTiesToEven) + return CannotBeNegativeZero(Call->getArgOperand(0), TLI, Depth + 1); + else + return false; + } // fabs(x) != -0.0 case Intrinsic::fabs: return true; + // sitofp and uitofp turn into +0.0 for zero. + case Intrinsic::experimental_constrained_sitofp: + case Intrinsic::experimental_constrained_uitofp: + return true; } } diff --git a/llvm/test/Transforms/InstSimplify/strictfp-fsub.ll b/llvm/test/Transforms/InstSimplify/strictfp-fsub.ll --- a/llvm/test/Transforms/InstSimplify/strictfp-fsub.ll +++ b/llvm/test/Transforms/InstSimplify/strictfp-fsub.ll @@ -216,12 +216,10 @@ ret float %sub } -; TODO: This can't fire currently due to missing constrained support: define float @fold_fsub_sitofp_x_n0_defaultenv(i32 %a) #0 { ; CHECK-LABEL: @fold_fsub_sitofp_x_n0_defaultenv( ; CHECK-NEXT: [[FPA:%.*]] = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] -; CHECK-NEXT: [[SUB:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[FPA]], float -0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] -; CHECK-NEXT: ret float [[SUB]] +; CHECK-NEXT: ret float [[FPA]] ; %fpa = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 %sub = call float @llvm.experimental.constrained.fsub.f32(float %fpa, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 diff --git a/llvm/test/Transforms/InstSimplify/strictfp-sqrt-nonneg.ll b/llvm/test/Transforms/InstSimplify/strictfp-sqrt-nonneg.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/strictfp-sqrt-nonneg.ll @@ -0,0 +1,222 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -passes=instsimplify -S | FileCheck %s + +; +; Check constrained detection of cases where negative zero is impossible: +; + +define float @nonneg_u_defaultenv(i32 %a) #0 { +; CHECK-LABEL: @nonneg_u_defaultenv( +; CHECK-NEXT: [[FPA:%.*]] = call float @llvm.experimental.constrained.uitofp.f32.i32(i32 [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0:[0-9]+]] +; CHECK-NEXT: [[SQRA:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[FPA]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[SQRA]] +; + %fpa = call float @llvm.experimental.constrained.uitofp.f32.i32(i32 %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + %sqra = call float @llvm.experimental.constrained.sqrt.f32(float %fpa, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + %sub = call float @llvm.experimental.constrained.fsub.f32(float %sqra, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %sub +} + +define float @nonneg_s_defaultenv(i32 %a) #0 { +; CHECK-LABEL: @nonneg_s_defaultenv( +; CHECK-NEXT: [[FPA:%.*]] = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: [[SQRA:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[FPA]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[SQRA]] +; + %fpa = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + %sqra = call float @llvm.experimental.constrained.sqrt.f32(float %fpa, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + %sub = call float @llvm.experimental.constrained.fsub.f32(float %sqra, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %sub +} + +define float @nonneg_u_maytrap(i32 %a) #0 { +; CHECK-LABEL: @nonneg_u_maytrap( +; CHECK-NEXT: [[FPA:%.*]] = call float @llvm.experimental.constrained.uitofp.f32.i32(i32 [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.maytrap") #[[ATTR0]] +; CHECK-NEXT: [[SQRA:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[FPA]], metadata !"round.tonearest", metadata !"fpexcept.maytrap") #[[ATTR0]] +; CHECK-NEXT: ret float [[SQRA]] +; + %fpa = call float @llvm.experimental.constrained.uitofp.f32.i32(i32 %a, metadata !"round.tonearest", metadata !"fpexcept.maytrap") #0 + %sqra = call float @llvm.experimental.constrained.sqrt.f32(float %fpa, metadata !"round.tonearest", metadata !"fpexcept.maytrap") #0 + %sub = call nnan float @llvm.experimental.constrained.fsub.f32(float %sqra, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.maytrap") #0 + ret float %sub +} + +define float @nonneg_s_maytrap(i32 %a) #0 { +; CHECK-LABEL: @nonneg_s_maytrap( +; CHECK-NEXT: [[FPA:%.*]] = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.maytrap") #[[ATTR0]] +; CHECK-NEXT: [[SQRA:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[FPA]], metadata !"round.tonearest", metadata !"fpexcept.maytrap") #[[ATTR0]] +; CHECK-NEXT: ret float [[SQRA]] +; + %fpa = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 %a, metadata !"round.tonearest", metadata !"fpexcept.maytrap") #0 + %sqra = call float @llvm.experimental.constrained.sqrt.f32(float %fpa, metadata !"round.tonearest", metadata !"fpexcept.maytrap") #0 + %sub = call nnan float @llvm.experimental.constrained.fsub.f32(float %sqra, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.maytrap") #0 + ret float %sub +} + +; NOTE: The fsub instruction is expected to remain, but the result isn't used. +define float @nonneg_u_ebstrict(i32 %a) #0 { +; CHECK-LABEL: @nonneg_u_ebstrict( +; CHECK-NEXT: [[FPA:%.*]] = call float @llvm.experimental.constrained.uitofp.f32.i32(i32 [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: [[SQRA:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[FPA]], metadata !"round.tonearest", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: [[SUB:%.*]] = call nnan float @llvm.experimental.constrained.fsub.f32(float [[SQRA]], float -0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[SQRA]] +; + %fpa = call float @llvm.experimental.constrained.uitofp.f32.i32(i32 %a, metadata !"round.tonearest", metadata !"fpexcept.strict") #0 + %sqra = call float @llvm.experimental.constrained.sqrt.f32(float %fpa, metadata !"round.tonearest", metadata !"fpexcept.strict") #0 + %sub = call nnan float @llvm.experimental.constrained.fsub.f32(float %sqra, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.strict") #0 + ret float %sub +} + +; NOTE: The fsub instruction is expected to remain, but the result isn't used. +define float @nonneg_s_ebstrict(i32 %a) #0 { +; CHECK-LABEL: @nonneg_s_ebstrict( +; CHECK-NEXT: [[FPA:%.*]] = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: [[SQRA:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[FPA]], metadata !"round.tonearest", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: [[SUB:%.*]] = call nnan float @llvm.experimental.constrained.fsub.f32(float [[SQRA]], float -0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[SQRA]] +; + %fpa = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 %a, metadata !"round.tonearest", metadata !"fpexcept.strict") #0 + %sqra = call float @llvm.experimental.constrained.sqrt.f32(float %fpa, metadata !"round.tonearest", metadata !"fpexcept.strict") #0 + %sub = call nnan float @llvm.experimental.constrained.fsub.f32(float %sqra, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.strict") #0 + ret float %sub +} + +; Test all the rounding modes. Exception handling shouldn't matter. + +define float @nonneg_u_downward(i32 %a) #0 { +; CHECK-LABEL: @nonneg_u_downward( +; CHECK-NEXT: [[FPA:%.*]] = call float @llvm.experimental.constrained.uitofp.f32.i32(i32 [[A:%.*]], metadata !"round.downward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: [[SQRA:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[FPA]], metadata !"round.downward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: [[SUB:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[SQRA]], float -0.000000e+00, metadata !"round.downward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[SUB]] +; + %fpa = call float @llvm.experimental.constrained.uitofp.f32.i32(i32 %a, metadata !"round.downward", metadata !"fpexcept.ignore") #0 + %sqra = call float @llvm.experimental.constrained.sqrt.f32(float %fpa, metadata !"round.downward", metadata !"fpexcept.ignore") #0 + %sub = call float @llvm.experimental.constrained.fsub.f32(float %sqra, float -0.0, metadata !"round.downward", metadata !"fpexcept.ignore") #0 + ret float %sub +} + +define float @nonneg_s_downward(i32 %a) #0 { +; CHECK-LABEL: @nonneg_s_downward( +; CHECK-NEXT: [[FPA:%.*]] = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 [[A:%.*]], metadata !"round.downward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: [[SQRA:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[FPA]], metadata !"round.downward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: [[SUB:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[SQRA]], float -0.000000e+00, metadata !"round.downward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[SUB]] +; + %fpa = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 %a, metadata !"round.downward", metadata !"fpexcept.ignore") #0 + %sqra = call float @llvm.experimental.constrained.sqrt.f32(float %fpa, metadata !"round.downward", metadata !"fpexcept.ignore") #0 + %sub = call float @llvm.experimental.constrained.fsub.f32(float %sqra, float -0.0, metadata !"round.downward", metadata !"fpexcept.ignore") #0 + ret float %sub +} + +define float @nonneg_u_upward(i32 %a) #0 { +; CHECK-LABEL: @nonneg_u_upward( +; CHECK-NEXT: [[FPA:%.*]] = call float @llvm.experimental.constrained.uitofp.f32.i32(i32 [[A:%.*]], metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: [[SQRA:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[FPA]], metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: [[SUB:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[SQRA]], float -0.000000e+00, metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[SUB]] +; + %fpa = call float @llvm.experimental.constrained.uitofp.f32.i32(i32 %a, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + %sqra = call float @llvm.experimental.constrained.sqrt.f32(float %fpa, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + %sub = call float @llvm.experimental.constrained.fsub.f32(float %sqra, float -0.0, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %sub +} + +define float @nonneg_s_upward(i32 %a) #0 { +; CHECK-LABEL: @nonneg_s_upward( +; CHECK-NEXT: [[FPA:%.*]] = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 [[A:%.*]], metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: [[SQRA:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[FPA]], metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: [[SUB:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[SQRA]], float -0.000000e+00, metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[SUB]] +; + %fpa = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 %a, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + %sqra = call float @llvm.experimental.constrained.sqrt.f32(float %fpa, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + %sub = call float @llvm.experimental.constrained.fsub.f32(float %sqra, float -0.0, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %sub +} + +define float @nonneg_u_towardzero(i32 %a) #0 { +; CHECK-LABEL: @nonneg_u_towardzero( +; CHECK-NEXT: [[FPA:%.*]] = call float @llvm.experimental.constrained.uitofp.f32.i32(i32 [[A:%.*]], metadata !"round.towardzero", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: [[SQRA:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[FPA]], metadata !"round.towardzero", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: [[SUB:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[SQRA]], float -0.000000e+00, metadata !"round.towardzero", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[SUB]] +; + %fpa = call float @llvm.experimental.constrained.uitofp.f32.i32(i32 %a, metadata !"round.towardzero", metadata !"fpexcept.ignore") #0 + %sqra = call float @llvm.experimental.constrained.sqrt.f32(float %fpa, metadata !"round.towardzero", metadata !"fpexcept.ignore") #0 + %sub = call float @llvm.experimental.constrained.fsub.f32(float %sqra, float -0.0, metadata !"round.towardzero", metadata !"fpexcept.ignore") #0 + ret float %sub +} + +define float @nonneg_s_towardzero(i32 %a) #0 { +; CHECK-LABEL: @nonneg_s_towardzero( +; CHECK-NEXT: [[FPA:%.*]] = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 [[A:%.*]], metadata !"round.towardzero", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: [[SQRA:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[FPA]], metadata !"round.towardzero", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: [[SUB:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[SQRA]], float -0.000000e+00, metadata !"round.towardzero", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[SUB]] +; + %fpa = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 %a, metadata !"round.towardzero", metadata !"fpexcept.ignore") #0 + %sqra = call float @llvm.experimental.constrained.sqrt.f32(float %fpa, metadata !"round.towardzero", metadata !"fpexcept.ignore") #0 + %sub = call float @llvm.experimental.constrained.fsub.f32(float %sqra, float -0.0, metadata !"round.towardzero", metadata !"fpexcept.ignore") #0 + ret float %sub +} + +define float @nonneg_u_tonearestaway(i32 %a) #0 { +; CHECK-LABEL: @nonneg_u_tonearestaway( +; CHECK-NEXT: [[FPA:%.*]] = call float @llvm.experimental.constrained.uitofp.f32.i32(i32 [[A:%.*]], metadata !"round.tonearestaway", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: [[SQRA:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[FPA]], metadata !"round.tonearestaway", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: [[SUB:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[SQRA]], float -0.000000e+00, metadata !"round.tonearestaway", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[SUB]] +; + %fpa = call float @llvm.experimental.constrained.uitofp.f32.i32(i32 %a, metadata !"round.tonearestaway", metadata !"fpexcept.ignore") #0 + %sqra = call float @llvm.experimental.constrained.sqrt.f32(float %fpa, metadata !"round.tonearestaway", metadata !"fpexcept.ignore") #0 + %sub = call float @llvm.experimental.constrained.fsub.f32(float %sqra, float -0.0, metadata !"round.tonearestaway", metadata !"fpexcept.ignore") #0 + ret float %sub +} + +define float @nonneg_s_tonearestaway(i32 %a) #0 { +; CHECK-LABEL: @nonneg_s_tonearestaway( +; CHECK-NEXT: [[FPA:%.*]] = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 [[A:%.*]], metadata !"round.tonearestaway", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: [[SQRA:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[FPA]], metadata !"round.tonearestaway", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: [[SUB:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[SQRA]], float -0.000000e+00, metadata !"round.tonearestaway", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[SUB]] +; + %fpa = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 %a, metadata !"round.tonearestaway", metadata !"fpexcept.ignore") #0 + %sqra = call float @llvm.experimental.constrained.sqrt.f32(float %fpa, metadata !"round.tonearestaway", metadata !"fpexcept.ignore") #0 + %sub = call float @llvm.experimental.constrained.fsub.f32(float %sqra, float -0.0, metadata !"round.tonearestaway", metadata !"fpexcept.ignore") #0 + ret float %sub +} + +define float @nonneg_u_dynamic(i32 %a) #0 { +; CHECK-LABEL: @nonneg_u_dynamic( +; CHECK-NEXT: [[FPA:%.*]] = call float @llvm.experimental.constrained.uitofp.f32.i32(i32 [[A:%.*]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: [[SQRA:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[FPA]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: [[SUB:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[SQRA]], float -0.000000e+00, metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[SUB]] +; + %fpa = call float @llvm.experimental.constrained.uitofp.f32.i32(i32 %a, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 + %sqra = call float @llvm.experimental.constrained.sqrt.f32(float %fpa, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 + %sub = call float @llvm.experimental.constrained.fsub.f32(float %sqra, float -0.0, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 + ret float %sub +} + +define float @nonneg_s_dynamic(i32 %a) #0 { +; CHECK-LABEL: @nonneg_s_dynamic( +; CHECK-NEXT: [[FPA:%.*]] = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 [[A:%.*]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: [[SQRA:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[FPA]], metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: [[SUB:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[SQRA]], float -0.000000e+00, metadata !"round.dynamic", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[SUB]] +; + %fpa = call float @llvm.experimental.constrained.sitofp.f32.i32(i32 %a, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 + %sqra = call float @llvm.experimental.constrained.sqrt.f32(float %fpa, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 + %sub = call float @llvm.experimental.constrained.fsub.f32(float %sqra, float -0.0, metadata !"round.dynamic", metadata !"fpexcept.ignore") #0 + ret float %sub +} + +declare float @llvm.experimental.constrained.sqrt.f32(float, metadata, metadata) #0 +declare float @llvm.experimental.constrained.fsub.f32(float, float, metadata, metadata) #0 + +declare float @llvm.experimental.constrained.sitofp.f32.i32(i32, metadata, metadata) #0 +declare float @llvm.experimental.constrained.uitofp.f32.i32(i32, metadata, metadata) #0 + +attributes #0 = { strictfp }