blob: 43fb2e7108d2b20147a0d40b0b96615844480f1b [file] [log] [blame]
//===- llvm/Support/KnownFPClass.h - Stores known fplcass -------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file contains a class for representing known fpclasses used by
// computeKnownFPClass.
//
//===----------------------------------------------------------------------===//
#include "llvm/Support/KnownFPClass.h"
#include "llvm/Support/ErrorHandling.h"
using namespace llvm;
/// Return true if it's possible to assume IEEE treatment of input denormals in
/// \p F for \p Val.
static bool inputDenormalIsIEEE(DenormalMode Mode) {
return Mode.Input == DenormalMode::IEEE;
}
static bool inputDenormalIsIEEEOrPosZero(DenormalMode Mode) {
return Mode.Input == DenormalMode::IEEE ||
Mode.Input == DenormalMode::PositiveZero;
}
bool KnownFPClass::isKnownNeverLogicalZero(DenormalMode Mode) const {
return isKnownNeverZero() &&
(isKnownNeverSubnormal() || inputDenormalIsIEEE(Mode));
}
bool KnownFPClass::isKnownNeverLogicalNegZero(DenormalMode Mode) const {
return isKnownNeverNegZero() &&
(isKnownNeverNegSubnormal() || inputDenormalIsIEEEOrPosZero(Mode));
}
bool KnownFPClass::isKnownNeverLogicalPosZero(DenormalMode Mode) const {
if (!isKnownNeverPosZero())
return false;
// If we know there are no denormals, nothing can be flushed to zero.
if (isKnownNeverSubnormal())
return true;
switch (Mode.Input) {
case DenormalMode::IEEE:
return true;
case DenormalMode::PreserveSign:
// Negative subnormal won't flush to +0
return isKnownNeverPosSubnormal();
case DenormalMode::PositiveZero:
default:
// Both positive and negative subnormal could flush to +0
return false;
}
llvm_unreachable("covered switch over denormal mode");
}
void KnownFPClass::propagateDenormal(const KnownFPClass &Src,
DenormalMode Mode) {
KnownFPClasses = Src.KnownFPClasses;
// If we aren't assuming the source can't be a zero, we don't have to check if
// a denormal input could be flushed.
if (!Src.isKnownNeverPosZero() && !Src.isKnownNeverNegZero())
return;
// If we know the input can't be a denormal, it can't be flushed to 0.
if (Src.isKnownNeverSubnormal())
return;
if (!Src.isKnownNeverPosSubnormal() && Mode != DenormalMode::getIEEE())
KnownFPClasses |= fcPosZero;
if (!Src.isKnownNeverNegSubnormal() && Mode != DenormalMode::getIEEE()) {
if (Mode != DenormalMode::getPositiveZero())
KnownFPClasses |= fcNegZero;
if (Mode.Input == DenormalMode::PositiveZero ||
Mode.Output == DenormalMode::PositiveZero ||
Mode.Input == DenormalMode::Dynamic ||
Mode.Output == DenormalMode::Dynamic)
KnownFPClasses |= fcPosZero;
}
}
void KnownFPClass::propagateCanonicalizingSrc(const KnownFPClass &Src,
DenormalMode Mode) {
propagateDenormal(Src, Mode);
propagateNaN(Src, /*PreserveSign=*/true);
}