diff options
author | Leonard Chan <leonardchan@google.com> | 2018-06-20 17:19:40 +0000 |
---|---|---|
committer | Leonard Chan <leonardchan@google.com> | 2018-06-20 17:19:40 +0000 |
commit | 84dd23f357de28ff35ffb7343d72cbfc79e49130 (patch) | |
tree | 7ec94dafa03219c940a7dff6086b060e16fb9eb4 /lib/Lex/LiteralSupport.cpp | |
parent | 2e7bf27afabf7dd4fce58a26b0eee4b60c42f337 (diff) | |
download | clang-84dd23f357de28ff35ffb7343d72cbfc79e49130.tar.gz |
[Fixed Point Arithmetic] Fixed Point Precision Bits and Fixed Point Literals
This diff includes the logic for setting the precision bits for each primary fixed point type in the target info and logic for initializing a fixed point literal.
Fixed point literals are declared using the suffixes
```
hr: short _Fract
uhr: unsigned short _Fract
r: _Fract
ur: unsigned _Fract
lr: long _Fract
ulr: unsigned long _Fract
hk: short _Accum
uhk: unsigned short _Accum
k: _Accum
uk: unsigned _Accum
```
Errors are also thrown for illegal literal values
```
unsigned short _Accum u_short_accum = 256.0uhk; // expected-error{{the integral part of this literal is too large for this unsigned _Accum type}}
```
Differential Revision: https://reviews.llvm.org/D46915
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@335148 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Lex/LiteralSupport.cpp')
-rw-r--r-- | lib/Lex/LiteralSupport.cpp | 153 |
1 files changed, 151 insertions, 2 deletions
diff --git a/lib/Lex/LiteralSupport.cpp b/lib/Lex/LiteralSupport.cpp index af64ffef6c..e414f85e02 100644 --- a/lib/Lex/LiteralSupport.cpp +++ b/lib/Lex/LiteralSupport.cpp @@ -538,6 +538,7 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, saw_exponent = false; saw_period = false; saw_ud_suffix = false; + saw_fixed_point_suffix = false; isLong = false; isUnsigned = false; isLongLong = false; @@ -547,6 +548,8 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, isFloat16 = false; isFloat128 = false; MicrosoftInteger = 0; + isFract = false; + isAccum = false; hadError = false; if (*s == '0') { // parse radix @@ -568,6 +571,14 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, SuffixBegin = s; checkSeparator(TokLoc, s, CSK_AfterDigits); + // Initial scan to lookahead for fixed point suffix. + for (const char *c = s; c != ThisTokEnd; ++c) { + if (*c == 'r' || *c == 'k' || *c == 'R' || *c == 'K') { + saw_fixed_point_suffix = true; + break; + } + } + // Parse the suffix. At this point we can classify whether we have an FP or // integer constant. bool isFPConstant = isFloatingLiteral(); @@ -576,11 +587,21 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, // we break out of the loop. for (; s != ThisTokEnd; ++s) { switch (*s) { + case 'R': + case 'r': + if (isFract || isAccum) break; + isFract = true; + continue; + case 'K': + case 'k': + if (isFract || isAccum) break; + isAccum = true; + continue; case 'h': // FP Suffix for "half". case 'H': // OpenCL Extension v1.2 s9.5 - h or H suffix for half type. - if (!PP.getLangOpts().Half) break; - if (!isFPConstant) break; // Error for integer constant. + if (!(PP.getLangOpts().Half || PP.getLangOpts().FixedPoint)) break; + if (isIntegerLiteral()) break; // Error for integer constant. if (isHalf || isFloat || isLong) break; // HH, FH, LH invalid. isHalf = true; continue; // Success. @@ -693,6 +714,9 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, isHalf = false; isImaginary = false; MicrosoftInteger = 0; + saw_fixed_point_suffix = false; + isFract = false; + isAccum = false; } saw_ud_suffix = true; @@ -707,6 +731,11 @@ NumericLiteralParser::NumericLiteralParser(StringRef TokSpelling, hadError = true; } } + + if (!hadError && saw_fixed_point_suffix) { + assert(isFract || isAccum); + assert(radix == 16 || radix == 10); + } } /// ParseDecimalOrOctalCommon - This method is called for decimal or octal @@ -1012,6 +1041,126 @@ NumericLiteralParser::GetFloatValue(llvm::APFloat &Result) { return Result.convertFromString(Str, APFloat::rmNearestTiesToEven); } +static inline bool IsExponentPart(char c) { + return c == 'p' || c == 'P' || c == 'e' || c == 'E'; +} + +bool NumericLiteralParser::GetFixedPointValue(llvm::APInt &StoreVal, unsigned Scale) { + assert(radix == 16 || radix == 10); + + // Find how many digits are needed to store the whole literal. + unsigned NumDigits = SuffixBegin - DigitsBegin; + if (saw_period) --NumDigits; + + // Initial scan of the exponent if it exists + bool ExpOverflowOccurred = false; + bool NegativeExponent = false; + const char *ExponentBegin; + uint64_t Exponent = 0; + int64_t BaseShift = 0; + if (saw_exponent) { + const char *Ptr = DigitsBegin; + + while (!IsExponentPart(*Ptr)) ++Ptr; + ExponentBegin = Ptr; + ++Ptr; + NegativeExponent = *Ptr == '-'; + if (NegativeExponent) ++Ptr; + + unsigned NumExpDigits = SuffixBegin - Ptr; + if (alwaysFitsInto64Bits(radix, NumExpDigits)) { + llvm::StringRef ExpStr(Ptr, NumExpDigits); + llvm::APInt ExpInt(/*numBits=*/64, ExpStr, /*radix=*/10); + Exponent = ExpInt.getZExtValue(); + } else { + ExpOverflowOccurred = true; + } + + if (NegativeExponent) BaseShift -= Exponent; + else BaseShift += Exponent; + } + + // Number of bits needed for decimal literal is + // ceil(NumDigits * log2(10)) Integral part + // + Scale Fractional part + // + ceil(Exponent * log2(10)) Exponent + // -------------------------------------------------- + // ceil((NumDigits + Exponent) * log2(10)) + Scale + // + // But for simplicity in handling integers, we can round up log2(10) to 4, + // making: + // 4 * (NumDigits + Exponent) + Scale + // + // Number of digits needed for hexadecimal literal is + // 4 * NumDigits Integral part + // + Scale Fractional part + // + Exponent Exponent + // -------------------------------------------------- + // (4 * NumDigits) + Scale + Exponent + uint64_t NumBitsNeeded; + if (radix == 10) + NumBitsNeeded = 4 * (NumDigits + Exponent) + Scale; + else + NumBitsNeeded = 4 * NumDigits + Exponent + Scale; + + if (NumBitsNeeded > std::numeric_limits<unsigned>::max()) + ExpOverflowOccurred = true; + llvm::APInt Val(static_cast<unsigned>(NumBitsNeeded), 0, /*isSigned=*/false); + + bool FoundDecimal = false; + + int64_t FractBaseShift = 0; + const char *End = saw_exponent ? ExponentBegin : SuffixBegin; + for (const char *Ptr = DigitsBegin; Ptr < End; ++Ptr) { + if (*Ptr == '.') { + FoundDecimal = true; + continue; + } + + // Normal reading of an integer + unsigned C = llvm::hexDigitValue(*Ptr); + assert(C < radix && "NumericLiteralParser ctor should have rejected this"); + + Val *= radix; + Val += C; + + if (FoundDecimal) + // Keep track of how much we will need to adjust this value by from the + // number of digits past the radix point. + --FractBaseShift; + } + + // For a radix of 16, we will be multiplying by 2 instead of 16. + if (radix == 16) FractBaseShift *= 4; + BaseShift += FractBaseShift; + + Val <<= Scale; + + uint64_t Base = (radix == 16) ? 2 : 10; + if (BaseShift > 0) { + for (int64_t i = 0; i < BaseShift; ++i) { + Val *= Base; + } + } else if (BaseShift < 0) { + for (int64_t i = BaseShift; i < 0 && !Val.isNullValue(); ++i) + Val = Val.udiv(Base); + } + + bool IntOverflowOccurred = false; + auto MaxVal = llvm::APInt::getMaxValue(StoreVal.getBitWidth()); + if (Val.getBitWidth() > StoreVal.getBitWidth()) { + IntOverflowOccurred |= Val.ugt(MaxVal.zext(Val.getBitWidth())); + StoreVal = Val.trunc(StoreVal.getBitWidth()); + } else if (Val.getBitWidth() < StoreVal.getBitWidth()) { + IntOverflowOccurred |= Val.zext(MaxVal.getBitWidth()).ugt(MaxVal); + StoreVal = Val.zext(StoreVal.getBitWidth()); + } else { + StoreVal = Val; + } + + return IntOverflowOccurred || ExpOverflowOccurred; +} + /// \verbatim /// user-defined-character-literal: [C++11 lex.ext] /// character-literal ud-suffix |