[llvm] d3919a8 - [ConstantFolding] Respect denormal handling mode attributes when folding instructions
David Candler via llvm-commits
llvm-commits at lists.llvm.org
Mon Jun 20 08:43:06 PDT 2022
Author: David Candler
Date: 2022-06-20T16:41:46+01:00
New Revision: d3919a8cc5031fd3d8c1ce3188abc0d7551306fb
URL: https://github.com/llvm/llvm-project/commit/d3919a8cc5031fd3d8c1ce3188abc0d7551306fb
DIFF: https://github.com/llvm/llvm-project/commit/d3919a8cc5031fd3d8c1ce3188abc0d7551306fb.diff
LOG: [ConstantFolding] Respect denormal handling mode attributes when folding instructions
Depending on the environment, a floating point instruction should
treat denormal inputs as zero, and/or flush a denormal output to zero.
Denormals are not currently accounted for when an instruction gets
folded to a constant, which can lead to differences in output between
a folded and a unfolded instruction when running on the target. The
denormal handling mode can be set by the function level attribute
denormal-fp-math, which this patch uses to determine whether any
denormal inputs to or outputs from folding should be zero, and that
the sign is set appropriately.
Reviewed By: spatel
Differential Revision: https://reviews.llvm.org/D116952
Added:
Modified:
llvm/include/llvm/Analysis/ConstantFolding.h
llvm/lib/Analysis/ConstantFolding.cpp
llvm/lib/Analysis/InstructionSimplify.cpp
llvm/test/Transforms/InstSimplify/constant-fold-fp-denormal.ll
Removed:
################################################################################
diff --git a/llvm/include/llvm/Analysis/ConstantFolding.h b/llvm/include/llvm/Analysis/ConstantFolding.h
index 230a64ccd0894..4f62e89c4b44e 100644
--- a/llvm/include/llvm/Analysis/ConstantFolding.h
+++ b/llvm/include/llvm/Analysis/ConstantFolding.h
@@ -85,6 +85,13 @@ Constant *ConstantFoldUnaryOpOperand(unsigned Opcode, Constant *Op,
Constant *ConstantFoldBinaryOpOperands(unsigned Opcode, Constant *LHS,
Constant *RHS, const DataLayout &DL);
+/// Attempt to constant fold a floating point binary operation with the
+/// specified operands, applying the denormal handling mod to the operands. If
+/// it fails, it returns a constant expression of the specified operands.
+Constant *ConstantFoldFPInstOperands(unsigned Opcode, Constant *LHS,
+ Constant *RHS, const DataLayout &DL,
+ const Instruction *I);
+
/// Attempt to constant fold a select instruction with the specified
/// operands. The constant result is returned if successful; if not, null is
/// returned.
diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp
index 7ca988697f032..6b8525a0414d8 100644
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -999,8 +999,24 @@ Constant *ConstantFoldInstOperandsImpl(const Value *InstOrCE, unsigned Opcode,
if (Instruction::isUnaryOp(Opcode))
return ConstantFoldUnaryOpOperand(Opcode, Ops[0], DL);
- if (Instruction::isBinaryOp(Opcode))
+ if (Instruction::isBinaryOp(Opcode)) {
+ switch (Opcode) {
+ default:
+ break;
+ case Instruction::FAdd:
+ case Instruction::FSub:
+ case Instruction::FMul:
+ case Instruction::FDiv:
+ case Instruction::FRem:
+ // Handle floating point instructions separately to account for denormals
+ // TODO: If a constant expression is being folded rather than an
+ // instruction, denormals will not be flushed/treated as zero
+ if (const auto *I = dyn_cast<Instruction>(InstOrCE)) {
+ return ConstantFoldFPInstOperands(Opcode, Ops[0], Ops[1], DL, I);
+ }
+ }
return ConstantFoldBinaryOpOperands(Opcode, Ops[0], Ops[1], DL);
+ }
if (Instruction::isCast(Opcode))
return ConstantFoldCastOperand(Opcode, Ops[0], DestTy, DL);
@@ -1295,6 +1311,63 @@ Constant *llvm::ConstantFoldBinaryOpOperands(unsigned Opcode, Constant *LHS,
return ConstantExpr::get(Opcode, LHS, RHS);
}
+// Check whether a constant is a floating point denormal that should be flushed
+// to zero according to the denormal handling mode set in the function
+// attributes. If so, return a zero with the correct sign, otherwise return the
+// original constant. Inputs and outputs to floating point instructions can have
+// their mode set separately, so the direction is also needed.
+Constant *FlushFPConstant(Constant *Operand, const llvm::Function *F,
+ bool IsOutput) {
+ if (F == nullptr)
+ return Operand;
+ if (auto *CFP = dyn_cast<ConstantFP>(Operand)) {
+ const APFloat &APF = CFP->getValueAPF();
+ Type *Ty = CFP->getType();
+ DenormalMode DenormMode = F->getDenormalMode(Ty->getFltSemantics());
+ DenormalMode::DenormalModeKind Mode =
+ IsOutput ? DenormMode.Output : DenormMode.Input;
+ switch (Mode) {
+ default:
+ llvm_unreachable("unknown denormal mode");
+ return Operand;
+ case DenormalMode::IEEE:
+ return Operand;
+ case DenormalMode::PreserveSign:
+ if (APF.isDenormal()) {
+ return ConstantFP::get(
+ Ty->getContext(),
+ APFloat::getZero(Ty->getFltSemantics(), APF.isNegative()));
+ }
+ return Operand;
+ case DenormalMode::PositiveZero:
+ if (APF.isDenormal()) {
+ return ConstantFP::get(Ty->getContext(),
+ APFloat::getZero(Ty->getFltSemantics(), false));
+ }
+ return Operand;
+ }
+ }
+ return Operand;
+}
+
+Constant *llvm::ConstantFoldFPInstOperands(unsigned Opcode, Constant *LHS,
+ Constant *RHS, const DataLayout &DL,
+ const Instruction *I) {
+ if (auto *BB = I->getParent()) {
+ if (auto *F = BB->getParent()) {
+ if (Instruction::isBinaryOp(Opcode)) {
+ Constant *Op0 = FlushFPConstant(LHS, F, false);
+ Constant *Op1 = FlushFPConstant(RHS, F, false);
+ Constant *C = ConstantFoldBinaryOpOperands(Opcode, Op0, Op1, DL);
+ return FlushFPConstant(C, F, true);
+ }
+ }
+ }
+ // If instruction lacks a parent/function and the denormal mode cannot be
+ // determined, use the default (IEEE).
+ return ConstantFoldBinaryOpOperands(Opcode, LHS, RHS, DL);
+}
+
Constant *llvm::ConstantFoldCastOperand(unsigned Opcode, Constant *C,
Type *DestTy, const DataLayout &DL) {
assert(Instruction::isCast(Opcode));
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 23ec186c2f572..07e3392c226e6 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -603,8 +603,20 @@ static Constant *foldOrCommuteConstant(Instruction::BinaryOps Opcode,
Value *&Op0, Value *&Op1,
const SimplifyQuery &Q) {
if (auto *CLHS = dyn_cast<Constant>(Op0)) {
- if (auto *CRHS = dyn_cast<Constant>(Op1))
+ if (auto *CRHS = dyn_cast<Constant>(Op1)) {
+ switch (Opcode) {
+ default:
+ break;
+ case Instruction::FAdd:
+ case Instruction::FSub:
+ case Instruction::FMul:
+ case Instruction::FDiv:
+ case Instruction::FRem:
+ if (Q.CxtI != nullptr)
+ return ConstantFoldFPInstOperands(Opcode, CLHS, CRHS, Q.DL, Q.CxtI);
+ }
return ConstantFoldBinaryOpOperands(Opcode, CLHS, CRHS, Q.DL);
+ }
// Canonicalize the constant to the RHS if this is a commutative operation.
if (Instruction::isCommutative(Opcode))
diff --git a/llvm/test/Transforms/InstSimplify/constant-fold-fp-denormal.ll b/llvm/test/Transforms/InstSimplify/constant-fold-fp-denormal.ll
index da1be758e30d7..24722c6560df5 100644
--- a/llvm/test/Transforms/InstSimplify/constant-fold-fp-denormal.ll
+++ b/llvm/test/Transforms/InstSimplify/constant-fold-fp-denormal.ll
@@ -21,39 +21,42 @@ define float @test_float_fadd_ieee() #0 {
define float @test_float_fadd_pzero_out() #1 {
; CHECK-LABEL: @test_float_fadd_pzero_out(
-; CHECK-NEXT: ret float 0xB800000000000000
-; default ieee mode leaves result as a denormal
+; CHECK-NEXT: ret float 0.000000e+00
+; denormal result is flushed to positive zero
%result = fadd float 0xB810000000000000, 0x3800000000000000
ret float %result
}
define float @test_float_fadd_psign_out() #2 {
; CHECK-LABEL: @test_float_fadd_psign_out(
-; CHECK-NEXT: ret float 0xB800000000000000
-; default ieee mode leaves result as a denormal
+; CHECK-NEXT: ret float -0.000000e+00
+; denormal result is flushed to sign preserved zero
%result = fadd float 0xB810000000000000, 0x3800000000000000
ret float %result
}
define float @test_float_fadd_pzero_in() #3 {
; CHECK-LABEL: @test_float_fadd_pzero_in(
-; CHECK-NEXT: ret float 0xB800000000000000
-; default ieee mode leaves result as a denormal
+; CHECK-NEXT: ret float 0xB810000000000000
+; denormal operand is treated as zero
+; normal operand added to zero results in the same operand as a result
%result = fadd float 0xB810000000000000, 0x3800000000000000
ret float %result
}
define float @test_float_fadd_psign_in() #4 {
; CHECK-LABEL: @test_float_fadd_psign_in(
-; CHECK-NEXT: ret float 0xB800000000000000
-; default ieee mode leaves result as a denormal
+; CHECK-NEXT: ret float 0xB810000000000000
+; denormal operand is treated as zero
+; normal operand added to zero results in the same operand as a result
%result = fadd float 0xB810000000000000, 0x3800000000000000
ret float %result
}
define float @test_float_fadd_pzero_f32_out() #5 {
; CHECK-LABEL: @test_float_fadd_pzero_f32_out(
-; CHECK-NEXT: ret float 0xB800000000000000
+; CHECK-NEXT: ret float 0.000000e+00
+; f32 only attribute should flush float output
; default ieee mode leaves result as a denormal
%result = fadd float 0xB810000000000000, 0x3800000000000000
ret float %result
@@ -69,32 +72,34 @@ define double @test_double_fadd_ieee() #0 {
define double @test_double_fadd_pzero_out() #1 {
; CHECK-LABEL: @test_double_fadd_pzero_out(
-; CHECK-NEXT: ret double 0x8008000000000000
-; default ieee mode leaves result as a denormal
+; CHECK-NEXT: ret double 0.000000e+00
+; denormal result is flushed to positive zero
%result = fadd double 0x8010000000000000, 0x8000000000000
ret double %result
}
define double @test_double_fadd_psign_out() #2 {
; CHECK-LABEL: @test_double_fadd_psign_out(
-; CHECK-NEXT: ret double 0x8008000000000000
-; default ieee mode leaves result as a denormal
+; CHECK-NEXT: ret double -0.000000e+00
+; denormal result is flushed to sign preserved zero
%result = fadd double 0x8010000000000000, 0x8000000000000
ret double %result
}
define double @test_double_fadd_pzero_in() #3 {
; CHECK-LABEL: @test_double_fadd_pzero_in(
-; CHECK-NEXT: ret double 0x8008000000000000
-; default ieee mode leaves result as a denormal
+; CHECK-NEXT: ret double 0x8010000000000000
+; denormal operand is treated as zero
+; normal operand added to zero results in the same operand as a result
%result = fadd double 0x8010000000000000, 0x8000000000000
ret double %result
}
define double @test_double_fadd_psign_in() #4 {
; CHECK-LABEL: @test_double_fadd_psign_in(
-; CHECK-NEXT: ret double 0x8008000000000000
-; default ieee mode leaves result as a denormal
+; CHECK-NEXT: ret double 0x8010000000000000
+; denormal operand is treated as zero
+; normal operand added to zero results in the same operand as a result
%result = fadd double 0x8010000000000000, 0x8000000000000
ret double %result
}
@@ -102,6 +107,7 @@ define double @test_double_fadd_psign_in() #4 {
define double @test_double_fadd_f32_ieee() #5 {
; CHECK-LABEL: @test_double_fadd_f32_ieee(
; CHECK-NEXT: ret double 0x8008000000000000
+; f32 only attribute should not flush doubles
; default ieee mode leaves result as a denormal
%result = fadd double 0x8010000000000000, 0x8000000000000
ret double %result
@@ -125,40 +131,43 @@ define float @test_float_fsub_ieee() #0 {
define float @test_float_fsub_pzero_out() #1 {
; CHECK-LABEL: @test_float_fsub_pzero_out(
-; CHECK-NEXT: ret float 0xB800000000000000
-; default ieee mode leaves result as a denormal
+; CHECK-NEXT: ret float 0.000000e+00
+; denormal result is flushed to positive zero
%result = fsub float 0x3800000000000000, 0x3810000000000000
ret float %result
}
define float @test_float_fsub_psign_out() #2 {
; CHECK-LABEL: @test_float_fsub_psign_out(
-; CHECK-NEXT: ret float 0xB800000000000000
-; default ieee mode leaves result as a denormal
+; CHECK-NEXT: ret float -0.000000e+00
+; denormal result is flushed to sign preserved zero
%result = fsub float 0x3800000000000000, 0x3810000000000000
ret float %result
}
define float @test_float_fsub_pzero_in() #3 {
; CHECK-LABEL: @test_float_fsub_pzero_in(
-; CHECK-NEXT: ret float 0xB800000000000000
-; default ieee mode leaves result as a denormal
+; CHECK-NEXT: ret float 0xB810000000000000
+; denormal operand is treated as zero
+; normal operand subtracted from zero produces the same operand, negated
%result = fsub float 0x3800000000000000, 0x3810000000000000
ret float %result
}
define float @test_float_fsub_psign_in() #4 {
; CHECK-LABEL: @test_float_fsub_psign_in(
-; CHECK-NEXT: ret float 0xB800000000000000
-; default ieee mode leaves result as a denormal
+; CHECK-NEXT: ret float 0xB810000000000000
+; denormal operand is treated as zero
+; normal operand subtracted from zero produces the same operand, negated
%result = fsub float 0x3800000000000000, 0x3810000000000000
ret float %result
}
define float @test_float_fsub_pzero_f32_out() #5 {
; CHECK-LABEL: @test_float_fsub_pzero_f32_out(
-; CHECK-NEXT: ret float 0xB800000000000000
-; default ieee mode leaves result as a denormal
+; CHECK-NEXT: ret float 0.000000e+00
+; f32 only attribute should flush float output
+; same as pzero_out above
%result = fsub float 0x3800000000000000, 0x3810000000000000
ret float %result
}
@@ -173,32 +182,34 @@ define double @test_double_fsub_ieee() #0 {
define double @test_double_fsub_pzero_out() #1 {
; CHECK-LABEL: @test_double_fsub_pzero_out(
-; CHECK-NEXT: ret double 0x8008000000000000
-; default ieee mode leaves result as a denormal
+; CHECK-NEXT: ret double 0.000000e+00
+; denormal result is flushed to positive zero
%result = fsub double 0x8000000000000, 0x10000000000000
ret double %result
}
define double @test_double_fsub_psign_out() #2 {
; CHECK-LABEL: @test_double_fsub_psign_out(
-; CHECK-NEXT: ret double 0x8008000000000000
-; default ieee mode leaves result as a denormal
+; CHECK-NEXT: ret double -0.000000e+00
+; denormal result is flushed to sign preserved zero
%result = fsub double 0x8000000000000, 0x10000000000000
ret double %result
}
define double @test_double_fsub_pzero_in() #3 {
; CHECK-LABEL: @test_double_fsub_pzero_in(
-; CHECK-NEXT: ret double 0x8008000000000000
-; default ieee mode leaves result as a denormal
+; CHECK-NEXT: ret double 0x8010000000000000
+; denormal operand is treated as zero
+; normal operand subtracted from zero produces the same operand, negated
%result = fsub double 0x8000000000000, 0x10000000000000
ret double %result
}
define double @test_double_fsub_psign_in() #4 {
; CHECK-LABEL: @test_double_fsub_psign_in(
-; CHECK-NEXT: ret double 0x8008000000000000
-; default ieee mode leaves result as a denormal
+; CHECK-NEXT: ret double 0x8010000000000000
+; denormal operand is treated as zero
+; normal operand subtracted from zero produces the same operand, negated
%result = fsub double 0x8000000000000, 0x10000000000000
ret double %result
}
@@ -206,6 +217,7 @@ define double @test_double_fsub_psign_in() #4 {
define double @test_double_fsub_f32_ieee() #5 {
; CHECK-LABEL: @test_double_fsub_f32_ieee(
; CHECK-NEXT: ret double 0x8008000000000000
+; f32 only attribute should not flush doubles
; default ieee mode leaves result as a denormal
%result = fsub double 0x8000000000000, 0x10000000000000
ret double %result
@@ -231,40 +243,43 @@ define float @test_float_fmul_ieee() #0 {
define float @test_float_fmul_pzero_out() #1 {
; CHECK-LABEL: @test_float_fmul_pzero_out(
-; CHECK-NEXT: ret float 0xB800000000000000
-; default ieee mode leaves result as a denormal
+; CHECK-NEXT: ret float 0.000000e+00
+; denormal result is flushed to positive zero
%result = fmul float 0x3810000000000000, -5.000000e-01
ret float %result
}
define float @test_float_fmul_psign_out() #2 {
; CHECK-LABEL: @test_float_fmul_psign_out(
-; CHECK-NEXT: ret float 0xB800000000000000
-; default ieee mode leaves result as a denormal
+; CHECK-NEXT: ret float -0.000000e+00
+; denormal result is flushed to sign preserved zero
%result = fmul float 0x3810000000000000, -5.000000e-01
ret float %result
}
define float @test_float_fmul_pzero_in() #3 {
; CHECK-LABEL: @test_float_fmul_pzero_in(
-; CHECK-NEXT: ret float 0xB810000000000000
-; default ieee mode leaves result as a normal
+; CHECK-NEXT: ret float 0.000000e+00
+; denormal operand is treated as positive zero
+; anything multiplied by zero gives a zero result
%result = fmul float 0xB800000000000000, 2.000000e-00
ret float %result
}
define float @test_float_fmul_psign_in() #4 {
; CHECK-LABEL: @test_float_fmul_psign_in(
-; CHECK-NEXT: ret float 0xB810000000000000
-; default ieee mode leaves result as a normal
+; CHECK-NEXT: ret float -0.000000e+00
+; denormal operand is treated as signed zero
+; anything multiplied by zero gives a zero result
%result = fmul float 0xB800000000000000, 2.000000e-00
ret float %result
}
define float @test_float_fmul_pzero_f32_out() #1 {
; CHECK-LABEL: @test_float_fmul_pzero_f32_out(
-; CHECK-NEXT: ret float 0xB800000000000000
-; default ieee mode leaves result as a denormal
+; CHECK-NEXT: ret float 0.000000e+00
+; f32 only attribute should flush float output
+; same as pzero_out above
%result = fmul float 0x3810000000000000, -5.000000e-01
ret float %result
}
@@ -279,32 +294,34 @@ define double @test_double_fmul_ieee() #0 {
define double @test_double_fmul_pzero_out() #1 {
; CHECK-LABEL: @test_double_fmul_pzero_out(
-; CHECK-NEXT: ret double 0x8008000000000000
-; default ieee mode leaves result as a denormal
+; CHECK-NEXT: ret double 0.000000e+00
+; denormal result is flushed to positive zero
%result = fmul double 0x10000000000000, -5.000000e-01
ret double %result
}
define double @test_double_fmul_psign_out() #2 {
; CHECK-LABEL: @test_double_fmul_psign_out(
-; CHECK-NEXT: ret double 0x8008000000000000
-; default ieee mode leaves result as a denormal
+; CHECK-NEXT: ret double -0.000000e+00
+; denormal result is flushed to sign preserved zero
%result = fmul double 0x10000000000000, -5.000000e-01
ret double %result
}
define double @test_double_fmul_pzero_in() #3 {
; CHECK-LABEL: @test_double_fmul_pzero_in(
-; CHECK-NEXT: ret double 0x8010000000000000
-; default ieee mode leaves result as a normal
+; CHECK-NEXT: ret double 0.000000e+00
+; denormal operand is treated as positive zero
+; anything multiplied by zero gives a zero result
%result = fmul double 0x8008000000000000, 2.000000e-00
ret double %result
}
define double @test_double_fmul_psign_in() #4 {
; CHECK-LABEL: @test_double_fmul_psign_in(
-; CHECK-NEXT: ret double 0x8010000000000000
-; default ieee mode leaves result as a normal
+; CHECK-NEXT: ret double -0.000000e+00
+; denormal operand is treated as signed zero
+; anything multiplied by zero gives a zero result
%result = fmul double 0x8008000000000000, 2.000000e-00
ret double %result
}
@@ -312,6 +329,7 @@ define double @test_double_fmul_psign_in() #4 {
define double @test_double_fmul_f32_ieee() #5 {
; CHECK-LABEL: @test_double_fmul_f32_ieee(
; CHECK-NEXT: ret double 0x8008000000000000
+; f32 only attribute should not flush doubles
; default ieee mode leaves result as a denormal
%result = fmul double 0x10000000000000, -5.000000e-01
ret double %result
@@ -337,40 +355,43 @@ define float @test_float_fdiv_ieee() #0 {
define float @test_float_fdiv_pzero_out() #1 {
; CHECK-LABEL: @test_float_fdiv_pzero_out(
-; CHECK-NEXT: ret float 0xB800000000000000
-; default ieee mode leaves result as a denormal
+; CHECK-NEXT: ret float 0.000000e+00
+; denormal result is flushed to positive zero
%result = fdiv float 0x3810000000000000, -2.000000e-00
ret float %result
}
define float @test_float_fdiv_psign_out() #2 {
; CHECK-LABEL: @test_float_fdiv_psign_out(
-; CHECK-NEXT: ret float 0xB800000000000000
-; default ieee mode leaves result as a denormal
+; CHECK-NEXT: ret float -0.000000e+00
+; denormal result is flushed to sign preserved zero
%result = fdiv float 0x3810000000000000, -2.000000e-00
ret float %result
}
define float @test_float_fdiv_pzero_in() #3 {
; CHECK-LABEL: @test_float_fdiv_pzero_in(
-; CHECK-NEXT: ret float 0xB810000000000000
-; default ieee mode leaves result as a normal
+; CHECK-NEXT: ret float 0.000000e+00
+; denormal operand is treated as zero
+; zero divided by anything gives a zero result
%result = fdiv float 0xB800000000000000, 5.000000e-01
ret float %result
}
define float @test_float_fdiv_psign_in() #4 {
; CHECK-LABEL: @test_float_fdiv_psign_in(
-; CHECK-NEXT: ret float 0xB7F0000000000000
-; default ieee mode leaves result as a normal
+; CHECK-NEXT: ret float -0.000000e+00
+; denormal operand is treated as zero
+; zero divided by anything gives a zero result
%result = fmul float 0xB800000000000000, 5.000000e-01
ret float %result
}
define float @test_float_fdiv_pzero_f32_out() #1 {
; CHECK-LABEL: @test_float_fdiv_pzero_f32_out(
-; CHECK-NEXT: ret float 0xB800000000000000
-; default ieee mode leaves result as a denormal
+; CHECK-NEXT: ret float 0.000000e+00
+; f32 only attribute should flush float output
+; same as pzero_out above
%result = fdiv float 0x3810000000000000, -2.000000e-00
ret float %result
}
@@ -385,32 +406,34 @@ define double @test_double_fdiv_ieee() #0 {
define double @test_double_fdiv_pzero_out() #1 {
; CHECK-LABEL: @test_double_fdiv_pzero_out(
-; CHECK-NEXT: ret double 0x8008000000000000
-; default ieee mode leaves result as a denormal
+; CHECK-NEXT: ret double 0.000000e+00
+; denormal result is flushed to positive zero
%result = fdiv double 0x10000000000000, -2.000000e-00
ret double %result
}
define double @test_double_fdiv_psign_out() #2 {
; CHECK-LABEL: @test_double_fdiv_psign_out(
-; CHECK-NEXT: ret double 0x8008000000000000
-; default ieee mode leaves result as a denormal
+; CHECK-NEXT: ret double -0.000000e+00
+; denormal result is flushed to sign preserved zero
%result = fdiv double 0x10000000000000, -2.000000e-00
ret double %result
}
define double @test_double_fdiv_pzero_in() #3 {
; CHECK-LABEL: @test_double_fdiv_pzero_in(
-; CHECK-NEXT: ret double 0x8010000000000000
-; default ieee mode leaves result as a normal
+; CHECK-NEXT: ret double 0.000000e+00
+; denormal operand is treated as zero
+; zero divided by anything gives a zero result
%result = fdiv double 0x8008000000000000, 5.000000e-01
ret double %result
}
define double @test_double_fdiv_psign_in() #4 {
; CHECK-LABEL: @test_double_fdiv_psign_in(
-; CHECK-NEXT: ret double 0x8010000000000000
-; default ieee mode leaves result as a normal
+; CHECK-NEXT: ret double -0.000000e+00
+; denormal operand is treated as zero
+; zero divided by anything gives a zero result
%result = fdiv double 0x8008000000000000, 5.000000e-01
ret double %result
}
@@ -418,6 +441,7 @@ define double @test_double_fdiv_psign_in() #4 {
define double @test_double_fdiv_f32_ieee() #5 {
; CHECK-LABEL: @test_double_fdiv_f32_ieee(
; CHECK-NEXT: ret double 0x8008000000000000
+; f32 only attribute should not flush doubles
; default ieee mode leaves result as a denormal
%result = fdiv double 0x10000000000000, -2.000000e-00
ret double %result
@@ -443,16 +467,16 @@ define float @test_float_frem_ieee_out() #0 {
define float @test_float_frem_pzero_out() #1 {
; CHECK-LABEL: @test_float_frem_pzero_out(
-; CHECK-NEXT: ret float 0xB800000000000000
-; default ieee mode leaves result as a denormal
+; CHECK-NEXT: ret float 0.000000e+00
+; denormal result is flushed to positive zero
%result = frem float 0xB818000000000000, 0x3810000000000000
ret float %result
}
define float @test_float_frem_psign_out() #2 {
; CHECK-LABEL: @test_float_frem_psign_out(
-; CHECK-NEXT: ret float 0xB800000000000000
-; default ieee mode leaves result as a denormal
+; CHECK-NEXT: ret float -0.000000e+00
+; denormal result is flushed to sign preserved zero
%result = frem float 0xB818000000000000, 0x3810000000000000
ret float %result
}
@@ -467,24 +491,27 @@ define float @test_float_frem_ieee_in() #0 {
define float @test_float_frem_pzero_in() #3 {
; CHECK-LABEL: @test_float_frem_pzero_in(
-; CHECK-NEXT: ret float 0x3800000000000000
-; default ieee mode leaves result same as input
+; CHECK-NEXT: ret float 0.000000e+00
+; denormal operand is treated as zero
+; remainder is now zero
%result = frem float 0x3800000000000000, 2.000000e+00
ret float %result
}
define float @test_float_frem_psign_in() #4 {
; CHECK-LABEL: @test_float_frem_psign_in(
-; CHECK-NEXT: ret float 0x3800000000000000
-; default ieee mode leaves result same as input
+; CHECK-NEXT: ret float 0.000000e+00
+; denormal operand is treated as zero
+; remainder is now zero
%result = frem float 0x3800000000000000, 2.000000e+00
ret float %result
}
define float @test_float_frem_pzero_f32_out() #1 {
; CHECK-LABEL: @test_float_frem_pzero_f32_out(
-; CHECK-NEXT: ret float 0xB800000000000000
-; default ieee mode leaves result as a denormal
+; CHECK-NEXT: ret float 0.000000e+00
+; f32 only attribute should flush float output
+; same as pzero_out above
%result = frem float 0xB818000000000000, 0x3810000000000000
ret float %result
}
@@ -499,16 +526,16 @@ define double @test_double_frem_ieee_out() #0 {
define double @test_double_frem_pzero_out() #1 {
; CHECK-LABEL: @test_double_frem_pzero_out(
-; CHECK-NEXT: ret double 0x8008000000000000
-; default ieee mode leaves result as a denormal
+; CHECK-NEXT: ret double 0.000000e+00
+; denormal result is flushed to positive zero
%result = frem double 0x8018000000000000, 0x10000000000000
ret double %result
}
define double @test_double_frem_psign_out() #2 {
; CHECK-LABEL: @test_double_frem_psign_out(
-; CHECK-NEXT: ret double 0x8008000000000000
-; default ieee mode leaves result as a denormal
+; CHECK-NEXT: ret double -0.000000e+00
+; denormal result is flushed to sign preserved zero
%result = frem double 0x8018000000000000, 0x10000000000000
ret double %result
}
@@ -523,16 +550,18 @@ define double @test_double_frem_ieee_in() #0 {
define double @test_double_frem_pzero_in() #3 {
; CHECK-LABEL: @test_double_frem_pzero_in(
-; CHECK-NEXT: ret double 0x8000000000000
-; default ieee mode leaves result same as input
+; CHECK-NEXT: ret double 0.000000e+00
+; denormal operand is treated as zero
+; remainder is now zero
%result = frem double 0x8000000000000, 2.000000e+00
ret double %result
}
define double @test_double_frem_psign_in() #4 {
; CHECK-LABEL: @test_double_frem_psign_in(
-; CHECK-NEXT: ret double 0x8000000000000
-; default ieee mode leaves result same as input
+; CHECK-NEXT: ret double 0.000000e+00
+; denormal operand is treated as zero
+; remainder is now zero
%result = frem double 0x8000000000000, 2.000000e+00
ret double %result
}
@@ -540,6 +569,7 @@ define double @test_double_frem_psign_in() #4 {
define double @test_double_frem_f32_ieee() #5 {
; CHECK-LABEL: @test_double_frem_f32_ieee(
; CHECK-NEXT: ret double 0x8008000000000000
+; f32 only attribute should not flush doubles
; default ieee mode leaves result as a denormal
%result = frem double 0x8018000000000000, 0x10000000000000
ret double %result
More information about the llvm-commits
mailing list