[llvm] [LLVM][IR] Add constant range support for floating-point types (PR #86483)
NAKAMURA Takumi via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 25 02:36:23 PDT 2024
================
@@ -0,0 +1,249 @@
+//===- ConstantFPRange.cpp - ConstantFPRange implementation ---------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/IR/ConstantFPRange.h"
+#include "llvm/ADT/APFloat.h"
+#include "llvm/Analysis/ValueTracking.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+
+using namespace llvm;
+
+void ConstantFPRange::makeEmpty() {
+ auto &Sem = Lower.getSemantics();
+ Lower = APFloat::getInf(Sem, /*Negative=*/false);
+ Upper = APFloat::getInf(Sem, /*Negative=*/true);
+ MayBeQNaN = false;
+ MayBeSNaN = false;
+}
+
+void ConstantFPRange::makeFull() {
+ auto &Sem = Lower.getSemantics();
+ Lower = APFloat::getInf(Sem, /*Negative=*/true);
+ Upper = APFloat::getInf(Sem, /*Negative=*/false);
+ MayBeQNaN = true;
+ MayBeSNaN = true;
+}
+
+bool ConstantFPRange::isNaNOnly() const {
+ return Lower.isPosInfinity() && Upper.isNegInfinity();
+}
+
+ConstantFPRange::ConstantFPRange(const fltSemantics &Sem, bool IsFullSet)
+ : Lower(Sem, APFloat::uninitialized), Upper(Sem, APFloat::uninitialized) {
+ Lower = APFloat::getInf(Sem, /*Negative=*/IsFullSet);
+ Upper = APFloat::getInf(Sem, /*Negative=*/!IsFullSet);
+ MayBeQNaN = IsFullSet;
+ MayBeSNaN = IsFullSet;
+}
+
+ConstantFPRange::ConstantFPRange(const APFloat &Value)
+ : Lower(Value.getSemantics(), APFloat::uninitialized),
+ Upper(Value.getSemantics(), APFloat::uninitialized) {
+ if (Value.isNaN()) {
+ makeEmpty();
+ bool IsSNaN = Value.isSignaling();
+ MayBeQNaN = !IsSNaN;
+ MayBeSNaN = IsSNaN;
+ } else {
+ Lower = Upper = Value;
+ MayBeQNaN = MayBeSNaN = false;
+ }
+}
+
+// We treat that -0 is less than 0 here.
+static APFloat::cmpResult strictCompare(const APFloat &LHS,
+ const APFloat &RHS) {
+ assert(!LHS.isNaN() && !RHS.isNaN() && "Unordered compare");
+ if (LHS.isZero() && RHS.isZero()) {
+ if (LHS.isNegative() == RHS.isNegative())
+ return APFloat::cmpEqual;
+ return LHS.isNegative() ? APFloat::cmpLessThan : APFloat::cmpGreaterThan;
+ }
+ return LHS.compare(RHS);
+}
+
+static bool isNonCanonicalEmptySet(const APFloat &Lower, const APFloat &Upper) {
+ return strictCompare(Lower, Upper) == APFloat::cmpGreaterThan &&
+ !(Lower.isInfinity() && Upper.isInfinity());
+}
+
+static void canonicalizeRange(APFloat &Lower, APFloat &Upper) {
+ if (isNonCanonicalEmptySet(Lower, Upper)) {
+ Lower = APFloat::getInf(Lower.getSemantics(), /*Negative=*/false);
+ Upper = APFloat::getInf(Upper.getSemantics(), /*Negative=*/true);
+ }
+}
+
+ConstantFPRange::ConstantFPRange(APFloat LowerVal, APFloat UpperVal,
+ bool MayBeQNaN, bool MayBeSNaN)
+ : Lower(std::move(LowerVal)), Upper(std::move(UpperVal)) {
+ assert(&Lower.getSemantics() == &Upper.getSemantics() &&
+ "Should only use the same semantics");
+ assert(!isNonCanonicalEmptySet(Lower, Upper) && "Non-canonical form");
+ this->MayBeQNaN = MayBeQNaN;
+ this->MayBeSNaN = MayBeSNaN;
+}
+
+ConstantFPRange ConstantFPRange::getFinite(const fltSemantics &Sem) {
+ return ConstantFPRange(APFloat::getLargest(Sem, /*Negative=*/true),
+ APFloat::getLargest(Sem, /*Negative=*/false),
+ /*MayBeQNaN=*/false, /*MayBeSNaN=*/false);
+}
+
+ConstantFPRange ConstantFPRange::getNaNOnly(const fltSemantics &Sem,
+ bool MayBeQNaN, bool MayBeSNaN) {
+ return ConstantFPRange(APFloat::getInf(Sem, /*Negative=*/false),
+ APFloat::getInf(Sem, /*Negative=*/true), MayBeQNaN,
+ MayBeSNaN);
+}
+
+ConstantFPRange
+ConstantFPRange::makeAllowedFCmpRegion(FCmpInst::Predicate Pred,
+ const ConstantFPRange &Other) {
+ // TODO
+ return getFull(Other.getSemantics());
+}
+
+ConstantFPRange
+ConstantFPRange::makeSatisfyingFCmpRegion(FCmpInst::Predicate Pred,
+ const ConstantFPRange &Other) {
+ // TODO
+ return getEmpty(Other.getSemantics());
+}
+
+ConstantFPRange ConstantFPRange::makeExactFCmpRegion(FCmpInst::Predicate Pred,
+ const APFloat &Other) {
+ return makeAllowedFCmpRegion(Pred, ConstantFPRange(Other));
+}
+
+bool ConstantFPRange::fcmp(FCmpInst::Predicate Pred,
+ const ConstantFPRange &Other) const {
+ return makeSatisfyingFCmpRegion(Pred, Other).contains(*this);
+}
+
+bool ConstantFPRange::isFullSet() const {
+ return Lower.isNegInfinity() && Upper.isPosInfinity() && MayBeQNaN &&
+ MayBeSNaN;
+}
+
+bool ConstantFPRange::isEmptySet() const {
+ return Lower.isPosInfinity() && Upper.isNegInfinity() && !MayBeQNaN &&
+ !MayBeSNaN;
+}
+
+bool ConstantFPRange::contains(const APFloat &Val) const {
+ assert(&getSemantics() == &Val.getSemantics() &&
+ "Should only use the same semantics");
+
+ if (Val.isNaN())
+ return Val.isSignaling() ? MayBeSNaN : MayBeQNaN;
+ return strictCompare(Lower, Val) != APFloat::cmpGreaterThan &&
+ strictCompare(Val, Upper) != APFloat::cmpGreaterThan;
+}
+
+bool ConstantFPRange::contains(const ConstantFPRange &CR) const {
+ assert(&getSemantics() == &CR.getSemantics() &&
+ "Should only use the same semantics");
+
+ if (CR.MayBeQNaN && !MayBeQNaN)
+ return false;
+
+ if (CR.MayBeSNaN && !MayBeSNaN)
+ return false;
+
+ return strictCompare(Lower, CR.Lower) != APFloat::cmpGreaterThan &&
+ strictCompare(CR.Upper, Upper) != APFloat::cmpGreaterThan;
+}
+
+const APFloat *ConstantFPRange::getSingleElement() const {
+ if (MayBeSNaN || MayBeQNaN)
+ return nullptr;
+ return Lower.bitwiseIsEqual(Upper) ? &Lower : nullptr;
+}
+
+std::optional<bool> ConstantFPRange::getSignBit() const {
+ if (!MayBeSNaN && !MayBeQNaN && Lower.isNegative() == Upper.isNegative())
+ return Lower.isNegative();
+ return std::nullopt;
+}
+
+bool ConstantFPRange::operator==(const ConstantFPRange &CR) const {
+ if (MayBeSNaN != CR.MayBeSNaN || MayBeQNaN != CR.MayBeQNaN)
+ return false;
+ return Lower.bitwiseIsEqual(CR.Lower) && Upper.bitwiseIsEqual(CR.Upper);
+}
+
+FPClassTest ConstantFPRange::classify() const {
+ uint32_t Mask = fcNone;
+ if (MayBeSNaN)
+ Mask |= fcSNan;
+ if (MayBeQNaN)
+ Mask |= fcQNan;
+ if (!isNaNOnly()) {
+ FPClassTest LowerMask = Lower.classify();
+ FPClassTest UpperMask = Upper.classify();
+ assert(LowerMask <= UpperMask && "Range is nan-only.");
+ for (uint32_t I = LowerMask; I <= UpperMask; I <<= 1)
+ Mask |= I;
+ }
+ return static_cast<FPClassTest>(Mask);
+}
+
+KnownFPClass ConstantFPRange::toKnownFPClass() const {
+ KnownFPClass Result;
+ Result.KnownFPClasses = classify();
+ Result.SignBit = getSignBit();
+ return Result;
+}
----------------
chapuni wrote:
Could you move this to elsewhere?
https://github.com/llvm/llvm-project/pull/86483
More information about the llvm-commits
mailing list