Skip to content

Commit

Permalink
[Fixed Point Arithmetic] Fixed Point Precision Bits and Fixed Point L…
Browse files Browse the repository at this point in the history
…iterals

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

llvm-svn: 335148
  • Loading branch information
PiJoules committed Jun 20, 2018
1 parent 7e067ab commit db01c3a
Show file tree
Hide file tree
Showing 40 changed files with 1,175 additions and 50 deletions.
7 changes: 6 additions & 1 deletion clang/include/clang-c/Index.h
Expand Up @@ -2170,7 +2170,12 @@ enum CXCursorKind {
*/
CXCursor_ObjCAvailabilityCheckExpr = 148,

CXCursor_LastExpr = CXCursor_ObjCAvailabilityCheckExpr,
/**
* Fixed point literal
*/
CXCursor_FixedPointLiteral = 149,

CXCursor_LastExpr = CXCursor_FixedPointLiteral,

/* Statements */
CXCursor_FirstStmt = 200,
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/AST/ASTContext.h
Expand Up @@ -1947,6 +1947,9 @@ class ASTContext : public RefCountedBase<ASTContext> {
return getQualifiedType(type.getUnqualifiedType(), Qs);
}

unsigned char getFixedPointScale(QualType Ty) const;
unsigned char getFixedPointIBits(QualType Ty) const;

DeclarationNameInfo getNameForTemplate(TemplateName Name,
SourceLocation NameLoc) const;

Expand Down
41 changes: 41 additions & 0 deletions clang/include/clang/AST/Expr.h
Expand Up @@ -1351,6 +1351,47 @@ class IntegerLiteral : public Expr, public APIntStorage {
}
};

class FixedPointLiteral : public Expr, public APIntStorage {
SourceLocation Loc;
unsigned Scale;

/// \brief Construct an empty integer literal.
explicit FixedPointLiteral(EmptyShell Empty)
: Expr(FixedPointLiteralClass, Empty) {}

public:
FixedPointLiteral(const ASTContext &C, const llvm::APInt &V, QualType type,
SourceLocation l, unsigned Scale);

// Store the int as is without any bit shifting.
static FixedPointLiteral *CreateFromRawInt(const ASTContext &C,
const llvm::APInt &V,
QualType type, SourceLocation l,
unsigned Scale);

SourceLocation getLocStart() const LLVM_READONLY { return Loc; }
SourceLocation getLocEnd() const LLVM_READONLY { return Loc; }

/// \brief Retrieve the location of the literal.
SourceLocation getLocation() const { return Loc; }

void setLocation(SourceLocation Location) { Loc = Location; }

static bool classof(const Stmt *T) {
return T->getStmtClass() == FixedPointLiteralClass;
}

std::string getValueAsString(unsigned Radix) const;

// Iterators
child_range children() {
return child_range(child_iterator(), child_iterator());
}
const_child_range children() const {
return const_child_range(const_child_iterator(), const_child_iterator());
}
};

class CharacterLiteral : public Expr {
public:
enum CharacterKind {
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/AST/RecursiveASTVisitor.h
Expand Up @@ -2585,6 +2585,7 @@ DEF_TRAVERSE_STMT(CoyieldExpr, {

// These literals (all of them) do not need any action.
DEF_TRAVERSE_STMT(IntegerLiteral, {})
DEF_TRAVERSE_STMT(FixedPointLiteral, {})
DEF_TRAVERSE_STMT(CharacterLiteral, {})
DEF_TRAVERSE_STMT(FloatingLiteral, {})
DEF_TRAVERSE_STMT(ImaginaryLiteral, {})
Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/AST/Type.h
Expand Up @@ -30,6 +30,7 @@
#include "clang/Basic/Specifiers.h"
#include "clang/Basic/Visibility.h"
#include "llvm/ADT/APInt.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/ADT/None.h"
Expand Down Expand Up @@ -6546,6 +6547,12 @@ QualType DecayedType::getPointeeType() const {
return cast<PointerType>(Decayed)->getPointeeType();
}

// Get the decimal string representation of a fixed point type, represented
// as a scaled integer.
void FixedPointValueToString(SmallVectorImpl<char> &Str,
const llvm::APSInt &Val,
unsigned Scale, unsigned Radix);

} // namespace clang

#endif // LLVM_CLANG_AST_TYPE_H
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/DiagnosticCommonKinds.td
Expand Up @@ -168,6 +168,8 @@ def ext_clang_enable_if : Extension<"'enable_if' is a clang extension">,
InGroup<GccCompat>;
def ext_clang_diagnose_if : Extension<"'diagnose_if' is a clang extension">,
InGroup<GccCompat>;
def err_too_large_for_fixed_point : Error<
"this value is too large for this fixed point type">;
def err_fixed_point_not_enabled : Error<"compile with "
"'-ffixed-point' to enable fixed point types">;

Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/LangOptions.def
Expand Up @@ -305,6 +305,8 @@ ENUM_LANGOPT(ClangABICompat, ClangABI, 4, ClangABI::Latest,
COMPATIBLE_VALUE_LANGOPT(FunctionAlignment, 5, 0, "Default alignment for functions")

LANGOPT(FixedPoint, 1, 0, "fixed point types")
LANGOPT(SameFBits, 1, 0,
"unsigned and signed fixed point type having the same number of fractional bits")

#undef LANGOPT
#undef COMPATIBLE_LANGOPT
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/StmtNodes.td
Expand Up @@ -57,6 +57,7 @@ def Expr : Stmt<1>;
def PredefinedExpr : DStmt<Expr>;
def DeclRefExpr : DStmt<Expr>;
def IntegerLiteral : DStmt<Expr>;
def FixedPointLiteral : DStmt<Expr>;
def FloatingLiteral : DStmt<Expr>;
def ImaginaryLiteral : DStmt<Expr>;
def StringLiteral : DStmt<Expr>;
Expand Down
103 changes: 103 additions & 0 deletions clang/include/clang/Basic/TargetInfo.h
Expand Up @@ -74,12 +74,32 @@ class TargetInfo : public RefCountedBase<TargetInfo> {
unsigned char LargeArrayMinWidth, LargeArrayAlign;
unsigned char LongWidth, LongAlign;
unsigned char LongLongWidth, LongLongAlign;

// Fixed point bit widths
unsigned char ShortAccumWidth, ShortAccumAlign;
unsigned char AccumWidth, AccumAlign;
unsigned char LongAccumWidth, LongAccumAlign;
unsigned char ShortFractWidth, ShortFractAlign;
unsigned char FractWidth, FractAlign;
unsigned char LongFractWidth, LongFractAlign;

// If true, unsigned fixed point types have the same number of fractional bits
// as their signed counterparts. Otherwise, unsigned fixed point types have
// one more fractional bit than its corresponding signed type. This is false
// by default.
bool SameFBits;

// Fixed point integral and fractional bit sizes
// Saturated types share the same integral/fractional bits as their
// corresponding unsaturated types.
// For simplicity, the fractional bits in a _Fract type will be one less the
// width of that _Fract type. This leaves all signed _Fract types having no
// padding and unsigned _Fract types will only have 1 bit of padding after the
// sign if SameFBits is set.
unsigned char ShortAccumScale;
unsigned char AccumScale;
unsigned char LongAccumScale;

unsigned char SuitableAlign;
unsigned char DefaultAlignForAttributeAligned;
unsigned char MinGlobalAlign;
Expand Down Expand Up @@ -394,6 +414,84 @@ class TargetInfo : public RefCountedBase<TargetInfo> {
unsigned getLongFractWidth() const { return LongFractWidth; }
unsigned getLongFractAlign() const { return LongFractAlign; }

/// getShortAccumScale/IBits - Return the number of fractional/integral bits
/// in a 'signed short _Accum' type.
unsigned getShortAccumScale() const { return ShortAccumScale; }
unsigned getShortAccumIBits() const {
return ShortAccumWidth - ShortAccumScale - 1;
}

/// getAccumScale/IBits - Return the number of fractional/integral bits
/// in a 'signed _Accum' type.
unsigned getAccumScale() const { return AccumScale; }
unsigned getAccumIBits() const { return AccumWidth - AccumScale - 1; }

/// getLongAccumScale/IBits - Return the number of fractional/integral bits
/// in a 'signed long _Accum' type.
unsigned getLongAccumScale() const { return LongAccumScale; }
unsigned getLongAccumIBits() const {
return LongAccumWidth - LongAccumScale - 1;
}

/// getUnsignedShortAccumScale/IBits - Return the number of
/// fractional/integral bits in a 'unsigned short _Accum' type.
unsigned getUnsignedShortAccumScale() const {
return SameFBits ? ShortAccumScale : ShortAccumScale + 1;
}
unsigned getUnsignedShortAccumIBits() const {
return SameFBits ? getShortAccumIBits()
: ShortAccumWidth - getUnsignedShortAccumScale();
}

/// getUnsignedAccumScale/IBits - Return the number of fractional/integral
/// bits in a 'unsigned _Accum' type.
unsigned getUnsignedAccumScale() const {
return SameFBits ? AccumScale : AccumScale + 1;
}
unsigned getUnsignedAccumIBits() const {
return SameFBits ? getAccumIBits() : AccumWidth - getUnsignedAccumScale();
}

/// getUnsignedLongAccumScale/IBits - Return the number of fractional/integral
/// bits in a 'unsigned long _Accum' type.
unsigned getUnsignedLongAccumScale() const {
return SameFBits ? LongAccumScale : LongAccumScale + 1;
}
unsigned getUnsignedLongAccumIBits() const {
return SameFBits ? getLongAccumIBits()
: LongAccumWidth - getUnsignedLongAccumScale();
}

/// getShortFractScale - Return the number of fractional bits
/// in a 'signed short _Fract' type.
unsigned getShortFractScale() const { return ShortFractWidth - 1; }

/// getFractScale - Return the number of fractional bits
/// in a 'signed _Fract' type.
unsigned getFractScale() const { return FractWidth - 1; }

/// getLongFractScale - Return the number of fractional bits
/// in a 'signed long _Fract' type.
unsigned getLongFractScale() const { return LongFractWidth - 1; }

/// getUnsignedShortFractScale - Return the number of fractional bits
/// in a 'unsigned short _Fract' type.
unsigned getUnsignedShortFractScale() const {
return SameFBits ? getShortFractScale() : getShortFractScale() + 1;
}

/// getUnsignedFractScale - Return the number of fractional bits
/// in a 'unsigned _Fract' type.
unsigned getUnsignedFractScale() const {
return SameFBits ? getFractScale() : getFractScale() + 1;
}

/// getUnsignedLongFractScale - Return the number of fractional bits
/// in a 'unsigned long _Fract' type.
unsigned getUnsignedLongFractScale() const {
return SameFBits ? getLongFractScale() : getLongFractScale() + 1;
}

/// Determine whether the __int128 type is supported on this target.
virtual bool hasInt128Type() const {
return (getPointerWidth(0) >= 64) || getTargetOpts().ForceEnableInt128;
Expand Down Expand Up @@ -1189,6 +1287,11 @@ class TargetInfo : public RefCountedBase<TargetInfo> {
virtual ArrayRef<AddlRegName> getGCCAddlRegNames() const {
return None;
}

private:
// Assert the values for the fractional and integral bits for each fixed point
// type follow the restrictions given in clause 6.2.6.3 of N1169.
void CheckFixedPointBits() const;
};

} // end namespace clang
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Driver/Options.td
Expand Up @@ -893,6 +893,10 @@ def ffixed_point : Flag<["-"], "ffixed-point">, Group<f_Group>,
Flags<[CC1Option]>, HelpText<"Enable fixed point types">;
def fno_fixed_point : Flag<["-"], "fno-fixed-point">, Group<f_Group>,
HelpText<"Disable fixed point types">;
def fsame_fbits : Flag<["-"], "fsame-fbits">, Group<f_Group>,
Flags<[CC1Option]>,
HelpText<"Force each unsigned fixed point type to have the same number of fractional bits as its corresponding signed type">;
def fno_same_fbits : Flag<["-"], "fno-same-fbits">, Group<f_Group>;

// Begin sanitizer flags. These should all be core options exposed in all driver
// modes.
Expand Down
17 changes: 14 additions & 3 deletions clang/include/clang/Lex/LiteralSupport.h
Expand Up @@ -50,7 +50,7 @@ class NumericLiteralParser {

unsigned radix;

bool saw_exponent, saw_period, saw_ud_suffix;
bool saw_exponent, saw_period, saw_ud_suffix, saw_fixed_point_suffix;

SmallString<32> UDSuffixBuf;

Expand All @@ -69,11 +69,16 @@ class NumericLiteralParser {
bool isFloat128 : 1; // 1.0q
uint8_t MicrosoftInteger; // Microsoft suffix extension i8, i16, i32, or i64.

bool isFract : 1; // 1.0hr/r/lr/uhr/ur/ulr
bool isAccum : 1; // 1.0hk/k/lk/uhk/uk/ulk

bool isFixedPointLiteral() const { return saw_fixed_point_suffix; }

bool isIntegerLiteral() const {
return !saw_period && !saw_exponent;
return !saw_period && !saw_exponent && !isFixedPointLiteral();
}
bool isFloatingLiteral() const {
return saw_period || saw_exponent;
return (saw_period || saw_exponent) && !isFixedPointLiteral();
}

bool hasUDSuffix() const {
Expand Down Expand Up @@ -105,6 +110,12 @@ class NumericLiteralParser {
/// literal exactly, and false otherwise.
llvm::APFloat::opStatus GetFloatValue(llvm::APFloat &Result);

/// GetFixedPointValue - Convert this numeric literal value into a
/// scaled integer that represents this value. Returns true if an overflow
/// occurred when calculating the integral part of the scaled integer or
/// calculating the digit sequence of the exponent.
bool GetFixedPointValue(llvm::APInt &StoreVal, unsigned Scale);

private:

void ParseNumberStartingWithZero(SourceLocation TokLoc);
Expand Down

0 comments on commit db01c3a

Please sign in to comment.