Skip to content

Commit

Permalink
[ValueTracking] Fix computeKnownFPClass for fpext (#81972)
Browse files Browse the repository at this point in the history
This patch adds the missing `subnormal -> normal` part for `fpext` in
`computeKnownFPClass`.
Fixes the miscompilation reported by
#80941 (comment).

(cherry picked from commit a5865c3)
  • Loading branch information
dtcxzyw authored and tstellar committed Feb 20, 2024
1 parent c5e1885 commit b845f06
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 3 deletions.
7 changes: 6 additions & 1 deletion llvm/lib/Analysis/ValueTracking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5083,8 +5083,13 @@ void computeKnownFPClass(const Value *V, const APInt &DemandedElts,
Op->getOperand(0)->getType()->getScalarType()->getFltSemantics();

// All subnormal inputs should be in the normal range in the result type.
if (APFloat::isRepresentableAsNormalIn(SrcTy, DstTy))
if (APFloat::isRepresentableAsNormalIn(SrcTy, DstTy)) {
if (Known.KnownFPClasses & fcPosSubnormal)
Known.KnownFPClasses |= fcPosNormal;
if (Known.KnownFPClasses & fcNegSubnormal)
Known.KnownFPClasses |= fcNegNormal;
Known.knownNot(fcSubnormal);
}

// Sign bit of a nan isn't guaranteed.
if (!Known.isKnownNeverNaN())
Expand Down
34 changes: 32 additions & 2 deletions llvm/test/Transforms/Attributor/nofpclass-fpext.ll
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ define double @ret_fpext_f32_to_f64_nosub(float nofpclass(sub) %arg0) {
}

define double @ret_fpext_f32_to_f64_nonorm(float nofpclass(norm) %arg0) {
; CHECK-LABEL: define nofpclass(sub norm) double @ret_fpext_f32_to_f64_nonorm
; CHECK-LABEL: define nofpclass(sub) double @ret_fpext_f32_to_f64_nonorm
; CHECK-SAME: (float nofpclass(sub norm) [[ARG0:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[EXT:%.*]] = fpext float [[ARG0]] to double
; CHECK-NEXT: ret double [[EXT]]
Expand Down Expand Up @@ -482,7 +482,37 @@ define double @ret_fpext_bf16_f64_nosub(bfloat nofpclass(sub) %arg0) {
}

define double @ret_fpext_bf16_f64_nonorm(bfloat nofpclass(norm) %arg0) {
; CHECK-LABEL: define nofpclass(sub norm) double @ret_fpext_bf16_f64_nonorm
; CHECK-LABEL: define nofpclass(sub) double @ret_fpext_bf16_f64_nonorm
; CHECK-SAME: (bfloat nofpclass(sub norm) [[ARG0:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[EXT:%.*]] = fpext bfloat [[ARG0]] to double
; CHECK-NEXT: ret double [[EXT]]
;
%ext = fpext bfloat %arg0 to double
ret double %ext
}

define double @ret_fpext_bf16_f64_nonorm_psub(bfloat nofpclass(norm psub) %arg0) {
; CHECK-LABEL: define nofpclass(sub pnorm) double @ret_fpext_bf16_f64_nonorm_psub
; CHECK-SAME: (bfloat nofpclass(sub norm) [[ARG0:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[EXT:%.*]] = fpext bfloat [[ARG0]] to double
; CHECK-NEXT: ret double [[EXT]]
;
%ext = fpext bfloat %arg0 to double
ret double %ext
}

define double @ret_fpext_bf16_f64_nonorm_nsub(bfloat nofpclass(norm nsub) %arg0) {
; CHECK-LABEL: define nofpclass(sub nnorm) double @ret_fpext_bf16_f64_nonorm_nsub
; CHECK-SAME: (bfloat nofpclass(sub norm) [[ARG0:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[EXT:%.*]] = fpext bfloat [[ARG0]] to double
; CHECK-NEXT: ret double [[EXT]]
;
%ext = fpext bfloat %arg0 to double
ret double %ext
}

define double @ret_fpext_bf16_f64_nonorm_sub(bfloat nofpclass(norm sub) %arg0) {
; CHECK-LABEL: define nofpclass(sub norm) double @ret_fpext_bf16_f64_nonorm_sub
; CHECK-SAME: (bfloat nofpclass(sub norm) [[ARG0:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[EXT:%.*]] = fpext bfloat [[ARG0]] to double
; CHECK-NEXT: ret double [[EXT]]
Expand Down
32 changes: 32 additions & 0 deletions llvm/test/Transforms/InstCombine/pr80941.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
; RUN: opt -S -passes=instcombine < %s | FileCheck %s

define float @pr80941(float %arg) {
; CHECK-LABEL: define float @pr80941(
; CHECK-SAME: float [[ARG:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[COND:%.*]] = tail call i1 @llvm.is.fpclass.f32(float [[ARG]], i32 144)
; CHECK-NEXT: br i1 [[COND]], label [[IF_THEN:%.*]], label [[IF_EXIT:%.*]]
; CHECK: if.then:
; CHECK-NEXT: [[FPEXT:%.*]] = fpext float [[ARG]] to double
; CHECK-NEXT: [[SIGN:%.*]] = call double @llvm.copysign.f64(double 0.000000e+00, double [[FPEXT]])
; CHECK-NEXT: [[FPTRUNC:%.*]] = fptrunc double [[SIGN]] to float
; CHECK-NEXT: br label [[IF_EXIT]]
; CHECK: if.exit:
; CHECK-NEXT: [[RET:%.*]] = phi float [ [[FPTRUNC]], [[IF_THEN]] ], [ [[ARG]], [[ENTRY:%.*]] ]
; CHECK-NEXT: ret float [[RET]]
;
entry:
%cond = tail call i1 @llvm.is.fpclass.f32(float %arg, i32 144)
br i1 %cond, label %if.then, label %if.exit

if.then:
%fpext = fpext float %arg to double
%sign = call double @llvm.copysign.f64(double 0.000000e+00, double %fpext)
%fptrunc = fptrunc double %sign to float
br label %if.exit

if.exit:
%ret = phi float [ %fptrunc, %if.then ], [ %arg, %entry ]
ret float %ret
}

0 comments on commit b845f06

Please sign in to comment.