1*700637cbSDimitry Andric //===- llvm/Support/KnownFPClass.h - Stores known fplcass -------*- C++ -*-===//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric //
9*700637cbSDimitry Andric // This file contains a class for representing known fpclasses used by
10*700637cbSDimitry Andric // computeKnownFPClass.
11*700637cbSDimitry Andric //
12*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
13*700637cbSDimitry Andric
14*700637cbSDimitry Andric #include "llvm/Support/KnownFPClass.h"
15*700637cbSDimitry Andric #include "llvm/Support/ErrorHandling.h"
16*700637cbSDimitry Andric
17*700637cbSDimitry Andric using namespace llvm;
18*700637cbSDimitry Andric
19*700637cbSDimitry Andric /// Return true if it's possible to assume IEEE treatment of input denormals in
20*700637cbSDimitry Andric /// \p F for \p Val.
inputDenormalIsIEEE(DenormalMode Mode)21*700637cbSDimitry Andric static bool inputDenormalIsIEEE(DenormalMode Mode) {
22*700637cbSDimitry Andric return Mode.Input == DenormalMode::IEEE;
23*700637cbSDimitry Andric }
24*700637cbSDimitry Andric
inputDenormalIsIEEEOrPosZero(DenormalMode Mode)25*700637cbSDimitry Andric static bool inputDenormalIsIEEEOrPosZero(DenormalMode Mode) {
26*700637cbSDimitry Andric return Mode.Input == DenormalMode::IEEE ||
27*700637cbSDimitry Andric Mode.Input == DenormalMode::PositiveZero;
28*700637cbSDimitry Andric }
29*700637cbSDimitry Andric
isKnownNeverLogicalZero(DenormalMode Mode) const30*700637cbSDimitry Andric bool KnownFPClass::isKnownNeverLogicalZero(DenormalMode Mode) const {
31*700637cbSDimitry Andric return isKnownNeverZero() &&
32*700637cbSDimitry Andric (isKnownNeverSubnormal() || inputDenormalIsIEEE(Mode));
33*700637cbSDimitry Andric }
34*700637cbSDimitry Andric
isKnownNeverLogicalNegZero(DenormalMode Mode) const35*700637cbSDimitry Andric bool KnownFPClass::isKnownNeverLogicalNegZero(DenormalMode Mode) const {
36*700637cbSDimitry Andric return isKnownNeverNegZero() &&
37*700637cbSDimitry Andric (isKnownNeverNegSubnormal() || inputDenormalIsIEEEOrPosZero(Mode));
38*700637cbSDimitry Andric }
39*700637cbSDimitry Andric
isKnownNeverLogicalPosZero(DenormalMode Mode) const40*700637cbSDimitry Andric bool KnownFPClass::isKnownNeverLogicalPosZero(DenormalMode Mode) const {
41*700637cbSDimitry Andric if (!isKnownNeverPosZero())
42*700637cbSDimitry Andric return false;
43*700637cbSDimitry Andric
44*700637cbSDimitry Andric // If we know there are no denormals, nothing can be flushed to zero.
45*700637cbSDimitry Andric if (isKnownNeverSubnormal())
46*700637cbSDimitry Andric return true;
47*700637cbSDimitry Andric
48*700637cbSDimitry Andric switch (Mode.Input) {
49*700637cbSDimitry Andric case DenormalMode::IEEE:
50*700637cbSDimitry Andric return true;
51*700637cbSDimitry Andric case DenormalMode::PreserveSign:
52*700637cbSDimitry Andric // Negative subnormal won't flush to +0
53*700637cbSDimitry Andric return isKnownNeverPosSubnormal();
54*700637cbSDimitry Andric case DenormalMode::PositiveZero:
55*700637cbSDimitry Andric default:
56*700637cbSDimitry Andric // Both positive and negative subnormal could flush to +0
57*700637cbSDimitry Andric return false;
58*700637cbSDimitry Andric }
59*700637cbSDimitry Andric
60*700637cbSDimitry Andric llvm_unreachable("covered switch over denormal mode");
61*700637cbSDimitry Andric }
62*700637cbSDimitry Andric
propagateDenormal(const KnownFPClass & Src,DenormalMode Mode)63*700637cbSDimitry Andric void KnownFPClass::propagateDenormal(const KnownFPClass &Src,
64*700637cbSDimitry Andric DenormalMode Mode) {
65*700637cbSDimitry Andric KnownFPClasses = Src.KnownFPClasses;
66*700637cbSDimitry Andric // If we aren't assuming the source can't be a zero, we don't have to check if
67*700637cbSDimitry Andric // a denormal input could be flushed.
68*700637cbSDimitry Andric if (!Src.isKnownNeverPosZero() && !Src.isKnownNeverNegZero())
69*700637cbSDimitry Andric return;
70*700637cbSDimitry Andric
71*700637cbSDimitry Andric // If we know the input can't be a denormal, it can't be flushed to 0.
72*700637cbSDimitry Andric if (Src.isKnownNeverSubnormal())
73*700637cbSDimitry Andric return;
74*700637cbSDimitry Andric
75*700637cbSDimitry Andric if (!Src.isKnownNeverPosSubnormal() && Mode != DenormalMode::getIEEE())
76*700637cbSDimitry Andric KnownFPClasses |= fcPosZero;
77*700637cbSDimitry Andric
78*700637cbSDimitry Andric if (!Src.isKnownNeverNegSubnormal() && Mode != DenormalMode::getIEEE()) {
79*700637cbSDimitry Andric if (Mode != DenormalMode::getPositiveZero())
80*700637cbSDimitry Andric KnownFPClasses |= fcNegZero;
81*700637cbSDimitry Andric
82*700637cbSDimitry Andric if (Mode.Input == DenormalMode::PositiveZero ||
83*700637cbSDimitry Andric Mode.Output == DenormalMode::PositiveZero ||
84*700637cbSDimitry Andric Mode.Input == DenormalMode::Dynamic ||
85*700637cbSDimitry Andric Mode.Output == DenormalMode::Dynamic)
86*700637cbSDimitry Andric KnownFPClasses |= fcPosZero;
87*700637cbSDimitry Andric }
88*700637cbSDimitry Andric }
89*700637cbSDimitry Andric
propagateCanonicalizingSrc(const KnownFPClass & Src,DenormalMode Mode)90*700637cbSDimitry Andric void KnownFPClass::propagateCanonicalizingSrc(const KnownFPClass &Src,
91*700637cbSDimitry Andric DenormalMode Mode) {
92*700637cbSDimitry Andric propagateDenormal(Src, Mode);
93*700637cbSDimitry Andric propagateNaN(Src, /*PreserveSign=*/true);
94*700637cbSDimitry Andric }
95