summaryrefslogtreecommitdiffstats
path: root/clang/lib/Basic/FixedPoint.cpp
blob: 0aaa9af191d5830fb5aac84d460ce178d84c06f1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
//===- FixedPoint.cpp - Fixed point constant handling -----------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
/// \file
/// Defines the implementation for the fixed point number interface.
//
//===----------------------------------------------------------------------===//

#include "clang/Basic/FixedPoint.h"

namespace clang {

APFixedPoint APFixedPoint::convert(const FixedPointSemantics &DstSema) const {
  llvm::APSInt NewVal = Val;
  unsigned DstWidth = DstSema.getWidth();
  unsigned DstScale = DstSema.getScale();
  bool Upscaling = DstScale > getScale();

  if (Upscaling) {
    NewVal = NewVal.extend(NewVal.getBitWidth() + DstScale - getScale());
    NewVal <<= (DstScale - getScale());
  } else {
    NewVal >>= (getScale() - DstScale);
  }

  if (DstSema.isSaturated()) {
    auto Mask = llvm::APInt::getBitsSetFrom(
        NewVal.getBitWidth(),
        std::min(DstScale + DstSema.getIntegralBits(), NewVal.getBitWidth()));
    llvm::APInt Masked(NewVal & Mask);

    // Change in the bits above the sign
    if (!(Masked == Mask || Masked == 0))
      NewVal = NewVal.isNegative() ? Mask : ~Mask;

    if (!DstSema.isSigned() && NewVal.isNegative())
      NewVal = 0;
  }

  NewVal = NewVal.extOrTrunc(DstWidth);
  NewVal.setIsSigned(DstSema.isSigned());
  return APFixedPoint(NewVal, DstSema);
}

int APFixedPoint::compare(const APFixedPoint &Other) const {
  llvm::APSInt ThisVal = getValue();
  llvm::APSInt OtherVal = Other.getValue();
  bool ThisSigned = Val.isSigned();
  bool OtherSigned = OtherVal.isSigned();
  unsigned OtherScale = Other.getScale();
  unsigned OtherWidth = OtherVal.getBitWidth();

  unsigned CommonWidth = std::max(Val.getBitWidth(), OtherWidth);

  // Prevent overflow in the event the widths are the same but the scales differ
  CommonWidth += getScale() >= OtherScale ? getScale() - OtherScale
                                          : OtherScale - getScale();

  ThisVal = ThisVal.extOrTrunc(CommonWidth);
  OtherVal = OtherVal.extOrTrunc(CommonWidth);

  unsigned CommonScale = std::max(getScale(), OtherScale);
  ThisVal = ThisVal.shl(CommonScale - getScale());
  OtherVal = OtherVal.shl(CommonScale - OtherScale);

  if (ThisSigned && OtherSigned) {
    if (ThisVal.sgt(OtherVal))
      return 1;
    else if (ThisVal.slt(OtherVal))
      return -1;
  } else if (!ThisSigned && !OtherSigned) {
    if (ThisVal.ugt(OtherVal))
      return 1;
    else if (ThisVal.ult(OtherVal))
      return -1;
  } else if (ThisSigned && !OtherSigned) {
    if (ThisVal.isSignBitSet())
      return -1;
    else if (ThisVal.ugt(OtherVal))
      return 1;
    else if (ThisVal.ult(OtherVal))
      return -1;
  } else {
    // !ThisSigned && OtherSigned
    if (OtherVal.isSignBitSet())
      return 1;
    else if (ThisVal.ugt(OtherVal))
      return 1;
    else if (ThisVal.ult(OtherVal))
      return -1;
  }

  return 0;
}

APFixedPoint APFixedPoint::getMax(const FixedPointSemantics &Sema) {
  bool IsUnsigned = !Sema.isSigned();
  auto Val = llvm::APSInt::getMaxValue(Sema.getWidth(), IsUnsigned);
  if (IsUnsigned && Sema.hasUnsignedPadding())
    Val = Val.lshr(1);
  return APFixedPoint(Val, Sema);
}

APFixedPoint APFixedPoint::getMin(const FixedPointSemantics &Sema) {
  auto Val = llvm::APSInt::getMinValue(Sema.getWidth(), !Sema.isSigned());
  return APFixedPoint(Val, Sema);
}

FixedPointSemantics FixedPointSemantics::getCommonSemantics(
    const FixedPointSemantics &Other) const {
  unsigned CommonScale = std::max(getScale(), Other.getScale());
  unsigned CommonWidth =
      std::max(getIntegralBits(), Other.getIntegralBits()) + CommonScale;

  bool ResultIsSigned = isSigned() || Other.isSigned();
  bool ResultIsSaturated = isSaturated() || Other.isSaturated();
  bool ResultHasUnsignedPadding = false;
  if (!ResultIsSigned) {
    // Both are unsigned.
    ResultHasUnsignedPadding = hasUnsignedPadding() &&
                               Other.hasUnsignedPadding() && !ResultIsSaturated;
  }

  // If the result is signed, add an extra bit for the sign. Otherwise, if it is
  // unsigned and has unsigned padding, we only need to add the extra padding
  // bit back if we are not saturating.
  if (ResultIsSigned || ResultHasUnsignedPadding)
    CommonWidth++;

  return FixedPointSemantics(CommonWidth, CommonScale, ResultIsSigned,
                             ResultIsSaturated, ResultHasUnsignedPadding);
}

}  // namespace clang
OpenPOWER on IntegriCloud