[PATCH] D46915: [Fixed Point Arithmetic] Set Fixed Point Precision Bits and Create Fixed Point Literals

Bevin Hansson via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Wed May 23 01:32:32 PDT 2018


ebevhan added a comment.

You should not define the fixed-point precision as compiler macros at build configure time. The number of fractional bits (the scaling factor) should be added to TargetInfo as target-configurable variables/accessors, and an accessor should be added to ASTContext (we call it 'getFixedPointScale') to fetch the scaling factor of arbitrary fixed-point types.

As I mentioned on the mailing list, we would also like to solve the problem with different scaling factors on the signed and unsigned _Fract types. I'm not sure what the best approach is, but the simplest solution could perhaps be enabled with a target flag.

If the flag is true, the scaling factor of the unsigned _Fract types is the same as the signed ones and the MSB is padding. If the flag is false, the scaling factor of the unsigned _Fract types is one greater than the signed types and all of the bits are used.

-----

Overall, the literal parsing code seems very ad-hoc. Fixed-point values are just integers, it should be possible to process them in exact precision instead of relying on host system implementation details (using double) and floating point types.

I could provide patches from our downstream port, but there are a number of hurdles:

- DSP-C does a bunch of extra 'type promotion' when parsing fixed-point literals
- literals in DSP-C cannot contain the 'exponent notation' so the parsing routine cannot handle this
- the routine uses utility functions added to APInt in our LLVM branch

If you are interested I can share anyway so you can see how we have done it.



================
Comment at: include/clang/Lex/LiteralSupport.h:72
 
+  enum FixedPointType { FPT_UNSPECIFIED, FPT_ACCUM, FPT_FRACT };
+
----------------
Is there a reason this is not added as two fields 'isAccum' and 'isFract'?


================
Comment at: include/clang/Lex/LiteralSupport.h:75
+  // We use separate fields for fixed point sizes b/c the isHalf/isLong booleans
+  // assume that this literal is an integral type instead of fixed point type.
+  enum FixedPointSize { FPS_UNSPECIFIED, FPS_SHORT, FPS_LONG };
----------------
Shouldn't the flags be amended instead?


================
Comment at: lib/AST/ASTContext.cpp:1788
     case BuiltinType::UShortAccum:
+    case BuiltinType::ShortFract:
+    case BuiltinType::UShortFract:
----------------
See my comments on the _Accum patch.


================
Comment at: lib/AST/ASTDumper.cpp:2186
+  ColorScope Color(*this, ValueColor);
+  OS << " " << Node->getValue().toString(10, isSigned);
+}
----------------
This will not print as a fixed-point number.


================
Comment at: lib/AST/Expr.cpp:766
+  const auto *BT = type->getAs<BuiltinType>();
+  assert(BT && "Not a fixed point type!");
+  switch (BT->getKind()) {
----------------
Is this possible given the assertion above?


================
Comment at: lib/AST/Expr.cpp:767
+  assert(BT && "Not a fixed point type!");
+  switch (BT->getKind()) {
+    default:
----------------
There is no reason to have this switch.


================
Comment at: lib/AST/Expr.cpp:774
+    case BuiltinType::UShortFract:
+      assert(V.getBitWidth() == C.getIntWidth(type) &&
+             "Short fixed point type is not the correct size for constant.");
----------------
'getIntWidth' is likely the wrong accessor to use here. Fixed-point types are technically not ints.


================
Comment at: lib/AST/ExprConstant.cpp:9323
+      if (Value.isSigned() && Value.isMinSignedValue() && E->canOverflow() &&
+          !HandleOverflow(Info, E, -Value.extend(Value.getBitWidth() + 1),
+                          E->getType()))
----------------
Is signed fixed-point overflow actually considered undefined behavior? I'm not familiar with what Embedded-C says about this.

Also, this routine will likely print the wrong number for fixed-point values.


================
Comment at: lib/AST/ExprConstant.cpp:9328
+    }
+    case UO_Not: {
+      if (!Visit(E->getSubExpr())) return false;
----------------
I do not believe ~ is valid on fixed-point types.


================
Comment at: lib/AST/StmtPrinter.cpp:1532
+  bool isSigned = Node->getType()->isSignedFixedPointType();
+  OS << Node->getValue().toString(10, isSigned);
+
----------------
This will not print a fixed-point number.


================
Comment at: lib/CodeGen/CGExprAgg.cpp:675
+  case CK_IntegralToFixedPoint:
+    llvm_unreachable(
+        "AggExprEmitter::VisitCastExpr CK_IntegralToFixedPoint");  // TODO
----------------
This probably goes in the large default case below, as fixed-point types are not aggregates.


================
Comment at: lib/CodeGen/CGExprComplex.cpp:451
+    llvm_unreachable(
+        "ComplexExprEmitter::EmitCast CK_IntegralToFixedPoint");  // TODO
   case CK_Dependent: llvm_unreachable("dependent cast kind in IR gen!");
----------------
Same as the aggregate case.


================
Comment at: lib/CodeGen/CGExprScalar.cpp:1789
+      case BuiltinType::ShortAccum:
+        fbits = BUILTIN_SACCUM_FBIT;
+        break;
----------------
This should all use ASTContext accessors.


================
Comment at: lib/Sema/SemaExpr.cpp:1334
 
+  // Handle floating point types
+  if (LHSType->isFixedPointType() || RHSType->isFixedPointType()) {
----------------
Fixed-point types.


================
Comment at: lib/Sema/SemaExpr.cpp:1335
+  // Handle floating point types
+  if (LHSType->isFixedPointType() || RHSType->isFixedPointType()) {
+    return handleFixedPointConversion(*this, LHS, RHS, LHSType, RHSType,
----------------
Braces are not needed.


================
Comment at: lib/Sema/SemaExpr.cpp:3385
+
+    QualType floatingTy = Context.DoubleTy;
+    const llvm::fltSemantics &Format =
----------------
You cannot parse the literal as a double and then convert it. You cannot control how the value is parsed and you might lose bits.

You should parse it explicitly by hand as a scaled integer large enough to carry the literal and then scale it down and truncate it when you know what the final type will be.


================
Comment at: lib/Sema/SemaExpr.cpp:3397
+      case FPS_UNSPECIFIED:
+        bit_width = Context.getTargetInfo().getIntWidth();
+        break;
----------------
These (bit_width, fbits etc) should be collected from ASTContext after the type has been determined.


================
Comment at: lib/Sema/SemaExpr.cpp:3407
+
+    if (Literal.fixedPointType == FPT_ACCUM) {
+      if (isSigned) {
----------------
It should be possible to do this in a much more concise manner. In our port we do this with a table lookup indexed by the type selection bits.


================
Comment at: lib/Sema/SemaExpr.cpp:3483
+      assert(
+          (fbits + ibits + 1 <= bit_width) &&
+          "The total fractional, integral, and sign bits exceed the bit width");
----------------
It does not feel like verifying this is the responsibility of the literal parser.


================
Comment at: lib/Sema/SemaExpr.cpp:3490
+
+    using llvm::APFloat;
+    APFloat Val(Format);
----------------
As I mentioned above, please do not use floating point routines to parse the fixed-point literals.



Repository:
  rC Clang

https://reviews.llvm.org/D46915





More information about the cfe-commits mailing list