leonardchan created this revision.
leonardchan added a project: clang.
Herald added a subscriber: cfe-commits.

This patch is not actually up for review and meant to hold the remaining work 
done after https://reviews.llvm.org/D47017 but haven't submitted for review yet.

This patch contains:

- `mulifx()` family functions. This essentially performs multiplication on 
_Accum/long _Accum types with integers but returns an integer instead of fixed 
point type.
- Intrinsic wrapper functions for `log2()`/`log10()`. These were not specified 
in Embedded-C, but were requested by the networking team. These functions are 
able to calculate a value up to 31 bits of precision (same as the default long 
_Accum scale), and have an error within 1 unit of precision of the true answer 
(error < 1/2^31).
- Intrinsic wrapper function for `pow10()`. Also requested by the networking 
team, and can also calculate a value with up to 31 bits of precision and an 
error within 1 unit of precision of the true answer.
- Corrected logic for scalar conversions between fixed points and floats
- Starting code for `FX_FULL_PRECISION` pragma


Repository:
  rC Clang

https://reviews.llvm.org/D49876

Files:
  include/clang/Basic/Builtins.def
  include/clang/Basic/TokenKinds.def
  include/clang/Parse/Parser.h
  lib/AST/ASTContext.cpp
  lib/CodeGen/CGBuiltin.cpp
  lib/CodeGen/CGExprScalar.cpp
  lib/CodeGen/CodeGenFunction.h
  lib/Parse/ParsePragma.cpp
  lib/Parse/ParseStmt.cpp
  lib/Parse/Parser.cpp
  test/Frontend/fixed_point_all_conversions.c
  test/Frontend/fixed_point_mulifx_validation.c

Index: test/Frontend/fixed_point_mulifx_validation.c
===================================================================
--- /dev/null
+++ test/Frontend/fixed_point_mulifx_validation.c
@@ -0,0 +1,332 @@
+// RUN: %clang -ffixed-point --target=x86_64-linux -S -emit-llvm -o - %s | lli -force-interpreter=true
+
+// Check the results of various builtin functions provided under <stdfix.h>
+// These tests assume the defualt precision values are used and assumes an int
+// is 32 bits, so target an architecture that supports this.
+
+#define assert(b) if (!(b)) { return 1; }
+
+// TODO: Remove these after implementing the macros for minimum fixed point
+// values.
+#define FRACT_MIN (-0.5r - 0.5r)
+#define LFRACT_MIN (-0.5lr - 0.5lr)
+#define ACCUM_MIN (-32768.0k - 32768.0k)
+#define LACCUM_MIN (-2147483648.0lk - 2147483648.0lk)
+
+int main() {
+  /*********** mulir() ************/
+
+  // Zero
+  assert(mulir(0, 1.0r) == 0);
+  assert(mulir(1, 0.0r) == 0);
+
+  // One
+  assert(mulir(1, 1.0r) == 0);
+  assert(mulir(-1, 1.0r) == -1);
+  assert(mulir(1, FRACT_MIN) == -1);
+  assert(mulir(-1, FRACT_MIN) == 1);
+
+  // Fractional resolves to int
+  assert(mulir(10, 0.5r) == 5);
+  assert(mulir(10, -0.5r) == -5);
+  assert(mulir(-10, 0.5r) == -5);
+  assert(mulir(-10, -0.5r) == 5);
+
+  // Fractional result is missing and value truncates towards zero by default
+  assert(mulir(15, 0.5r) == 7);
+  assert(mulir(15, -0.5r) == -8);
+  assert(mulir(-15, 0.5r) == -8);
+  assert(mulir(-15, -0.5r) == 7);
+
+  // Limited resulution of the _Fract fractional bits does not always allow for
+  // the most precise values. 1.0r resolves to _Fract max.
+  assert(mulir(65536, 1.0r) == 65534);
+  assert(mulir(-65536, 1.0r) == -65534);
+  assert(mulir(65536, FRACT_MIN) == -65536);
+  assert(mulir(-65536, FRACT_MIN) == 65536);
+
+  assert(mulir(2147483647, 1.0r) == 2147418111);
+  assert(mulir(-2147483647, 1.0r) == -2147418112);  // Rounds down
+  assert(mulir(2147483647, FRACT_MIN) == -2147483647);
+  assert(mulir(-2147483647, FRACT_MIN) == 2147483647);
+
+  /*********** mulilr() ************/
+
+  // Zero
+  assert(mulilr(0, 1.0lr) == 0);
+  assert(mulilr(1, 0.0lr) == 0);
+
+  // One
+  assert(mulilr(1, 1.0lr) == 0);
+  assert(mulilr(-1, 1.0lr) == -1);
+  assert(mulilr(1, LFRACT_MIN) == -1);
+  assert(mulilr(-1, LFRACT_MIN) == 1);
+
+  // Fractional resolves to int
+  assert(mulilr(10, 0.5lr) == 5);
+  assert(mulilr(10, -0.5lr) == -5);
+  assert(mulilr(-10, 0.5lr) == -5);
+  assert(mulilr(-10, -0.5lr) == 5);
+
+  // Fractional result is missing and value truncates towards zero
+  assert(mulilr(15, 0.5lr) == 7);
+  assert(mulilr(15, -0.5lr) == -8);
+  assert(mulilr(-15, 0.5lr) == -8);
+  assert(mulilr(-15, -0.5lr) == 7);
+
+  // Limited resulution of the _Fract fractional bits does not always allow for
+  // the most precise values.
+  assert(mulilr(4294967296, 1.0lr) == 4294967294);
+  assert(mulilr(-4294967296, 1.0lr) == -4294967294);
+  assert(mulilr(4294967296, LFRACT_MIN) == -4294967296);
+  assert(mulilr(-4294967296, LFRACT_MIN) == 4294967296);
+
+  assert(mulilr(9223372036854775807, 1.0lr) == 9223372032559808511);
+  assert(mulilr(-9223372036854775807, 1.0lr) == -9223372032559808512);  // Rounds down
+  assert(mulilr(9223372036854775807, LFRACT_MIN) == -9223372036854775807);
+  assert(mulilr(-9223372036854775807, LFRACT_MIN) == 9223372036854775807);
+
+  /*********** mulik() ************/
+
+  // Zero
+  assert(mulik(0, 1.0k) == 0);
+  assert(mulik(1, 0.0k) == 0);
+
+  // One
+  assert(mulik(1, 1.0k) == 1);
+  assert(mulik(-1, 1.0k) == -1);
+  assert(mulik(1, -1.0k) == -1);
+  assert(mulik(-1, -1.0k) == 1);
+
+  // No fractional
+  assert(mulik(3, 4.0k) == 12);
+  assert(mulik(-3, 4.0k) == -12);
+  assert(mulik(3, -4.0k) == -12);
+  assert(mulik(-3, -4.0k) == 12);
+
+  // Fractional resolves to int
+  assert(mulik(2, 2.5k) == 5);
+  assert(mulik(2, -2.5k) == -5);
+  assert(mulik(-2, 2.5k) == -5);
+  assert(mulik(-2, -2.5k) == 5);
+
+  assert(mulik(10, 0.5k) == 5);
+  assert(mulik(10, -0.5k) == -5);
+  assert(mulik(-10, 0.5k) == -5);
+  assert(mulik(-10, -0.5k) == 5);
+
+  // Fractional result is missing and value truncates towards zero
+  assert(mulik(3, 2.5k) == 7);
+  assert(mulik(3, -2.5k) == -8);
+  assert(mulik(-3, 2.5k) == -8);
+  assert(mulik(-3, -2.5k) == 7);
+
+  assert(mulik(15, 0.5k) == 7);
+  assert(mulik(15, -0.5k) == -8);
+  assert(mulik(-15, 0.5k) == -8);
+  assert(mulik(-15, -0.5k) == 7);
+
+  // Limited resulution of the _Accum fractional bits does not always allow for
+  // the most precise values.
+  // 1 * _Accum limits
+  assert(mulik(1, 65535.99999999999k) == 65535);
+  assert(mulik(-1, 65535.99999999999k) == -65536);
+  assert(mulik(1, ACCUM_MIN) == -65536);
+  assert(mulik(-1, ACCUM_MIN) == 65536);
+
+  // _Accum limits as integer * near 1 _Accum (evenly divisibly)
+  assert(mulik(65536, 0.99999999999k) == 65534);
+  assert(mulik(-65536, 0.99999999999k) == -65534);
+  assert(mulik(65536, -0.99999999999k) == -65534);
+  assert(mulik(-65536, -0.99999999999k) == 65534);
+
+  // int max * near 1 _Accum
+  assert(mulik(2147483647, 0.99999999999k) == 2147418111);
+  assert(mulik(-2147483647, 0.99999999999k) == -2147418112);
+  assert(mulik(2147483647, -0.99999999999k) == -2147418112);
+  assert(mulik(-2147483647, -0.99999999999k) == 2147418111);
+
+  // int max * 1 _Accum (exact values)
+  assert(mulik(2147483647, 1.0k) == 2147483647);
+  assert(mulik(-2147483647, 1.0k) == -2147483647);
+  assert(mulik(2147483647, -1.0k) == -2147483647);
+  assert(mulik(2147483647, 1.0k) == 2147483647);
+
+  // int min * near 1 _Accum
+  assert(mulik(-2147483648, 0.99999999999k) == -2147418112);
+  assert(mulik(-2147483648, -0.99999999999k) == 2147418112);
+
+  /*********** mulilk() ************/
+
+  // Zero
+  assert(mulilk(0, 1.0lk) == 0);
+  assert(mulilk(1, 0.0lk) == 0);
+
+  // One
+  assert(mulilk(1, 1.0lk) == 1);
+  assert(mulilk(-1, 1.0lk) == -1);
+  assert(mulilk(1, -1.0lk) == -1);
+  assert(mulilk(-1, -1.0lk) == 1);
+
+  // Fractional resolves to int
+  assert(mulilk(2, 2.5lk) == 5);
+  assert(mulilk(2, -2.5lk) == -5);
+  assert(mulilk(-2, 2.5lk) == -5);
+  assert(mulilk(-2, -2.5lk) == 5);
+
+  assert(mulilk(10, 0.5lk) == 5);
+  assert(mulilk(10, -0.5lk) == -5);
+  assert(mulilk(-10, 0.5lk) == -5);
+  assert(mulilk(-10, -0.5lk) == 5);
+
+  // Fractional result is missing and value truncates towards zero
+  assert(mulilk(3, 2.5lk) == 7);
+  assert(mulilk(3, -2.5lk) == -8);
+  assert(mulilk(-3, 2.5lk) == -8);
+  assert(mulilk(-3, -2.5lk) == 7);
+
+  assert(mulilk(15, 0.5lk) == 7);
+  assert(mulilk(15, -0.5lk) == -8);
+  assert(mulilk(-15, 0.5lk) == -8);
+  assert(mulilk(-15, -0.5lk) == 7);
+
+  // Limited resulution of the _Accum fractional bits does not always allow for
+  // the most precise values.
+  // 1 * long _Accum limits
+  assert(mulilk(1, 4294967295.99999999999lk) == 4294967295);
+  assert(mulilk(-1, 4294967295.99999999999lk) == -4294967296);
+  assert(mulilk(1, LACCUM_MIN) == -4294967296);
+  assert(mulilk(-1, LACCUM_MIN) == 4294967296);
+
+  // long _Accum limits as integer * near 1 long _Accum (evenly divisibly)
+  assert(mulilk(4294967296L, 0.99999999999lk) == 4294967294);
+  assert(mulilk(-4294967296L, 0.99999999999lk) == -4294967294);
+  assert(mulilk(4294967296L, -0.99999999999lk) == -4294967294);
+  assert(mulilk(-4294967296L, -0.99999999999lk) == 4294967294);
+
+  // long int max * near 1 long _Accum
+  assert(mulilk(9223372036854775807L, 0.99999999999999999999lk) == 9223372032559808511L);
+  assert(mulilk(-9223372036854775807L, 0.99999999999999999999lk) == -9223372032559808512L);
+  assert(mulilk(9223372036854775807L, -0.99999999999999999999lk) == -9223372032559808512L);
+  assert(mulilk(-9223372036854775807L, -0.99999999999999999999lk) == 9223372032559808511L);
+
+  // long int max * 1 long _Accum (exact values)
+  assert(mulilk(9223372036854775807L, 1.0k) == 9223372036854775807L);
+  assert(mulilk(-9223372036854775807L, 1.0k) == -9223372036854775807L);
+  assert(mulilk(9223372036854775807L, -1.0k) == -9223372036854775807L);
+  assert(mulilk(-9223372036854775807L, -1.0k) == 9223372036854775807L);
+
+  // long int min * near 1 long _Accum
+  assert(mulilk(-9223372036854775808L, 0.99999999999lk) == -9223372032559808512L);
+  assert(mulilk(-9223372036854775808L, -0.99999999999lk) == 9223372032559808512L);
+
+  /*********** muliur() ************/
+
+  // Zero
+  assert(muliur(0, 1.0ur) == 0);
+  assert(muliur(1, 0.0ur) == 0);
+
+  // One
+  assert(muliur(1, 1.0ur) == 0);
+
+  // Fractional resolves to int
+  assert(muliur(10, 0.5ur) == 5);
+
+  // Fractional result is missing and value truncates towards zero by default
+  assert(muliur(15, 0.5ur) == 7);
+
+  // Limited resulution of the _Fract fractional bits does not always allow for
+  // the most precise values. 1.0ur resolves to _Fract max.
+  assert(muliur(65536, 1.0ur) == 65535);
+  assert(muliur(4294967295, 1.0ur) == 4294901759);
+
+  /*********** muliulr() ************/
+
+  // Zero
+  assert(muliulr(0, 1.0ulr) == 0);
+  assert(muliulr(1, 0.0ulr) == 0);
+
+  // One
+  assert(muliulr(1, 1.0ulr) == 0);
+
+  // Fractional resolves to int
+  assert(muliulr(10, 0.5ulr) == 5);
+
+  // Fractional result is missing and value truncates towards zero by default
+  assert(muliulr(15, 0.5ulr) == 7);
+
+  // Limited resulution of the _Fract fractional bits does not always allow for
+  // the most precise values. 1.0ur resolves to _Fract max.
+  assert(muliulr(4294967296, 1.0ulr) == 4294967295);
+  assert(muliulr(9223372036854775807, 1.0ulr) == 9223372034707292159);
+
+  /*********** muliuk() ************/
+
+  // Zero
+  assert(muliuk(0, 1.0uk) == 0);
+  assert(muliuk(1, 0.0uk) == 0);
+
+  // One
+  assert(muliuk(1, 1.0uk) == 1);
+
+  // No fractional
+  assert(muliuk(3, 4.0uk) == 12);
+
+  // Fractional resolves to int
+  assert(muliuk(2, 2.5uk) == 5);
+  assert(muliuk(10, 0.5uk) == 5);
+
+  // Fractional result is missing and value truncates towards zero
+  assert(muliuk(3, 2.5uk) == 7);
+  assert(muliuk(15, 0.5uk) == 7);
+
+  // Limited resulution of the _Accum fractional bits does not always allow for
+  // the most precise values.
+  // 1 * unsigned _Accum limits
+  assert(muliuk(1, 65535.99999999999uk) == 65535);
+
+  // unsigned _Accum limits as integer * near 1 unsigned _Accum (evenly divisibly)
+  assert(muliuk(65536, 0.99999999999uk) == 65535);
+
+  // unsigned int max * near 1 unsigned _Accum
+  assert(muliuk(4294967295, 0.99999999999uk) == 4294901759);
+
+  // unsigned int max * 1 unsigned _Accum (exact values)
+  assert(muliuk(4294967295, 1.0uk) == 4294967295);
+
+  /*********** muliulk() ************/
+
+  // Zero
+  assert(muliulk(0, 1.0ulk) == 0);
+  assert(muliulk(1, 0.0ulk) == 0);
+
+  // One
+  assert(muliulk(1, 1.0ulk) == 1);
+
+  // No fractional
+  assert(muliulk(3, 4.0ulk) == 12);
+
+  // Fractional resolves to int
+  assert(muliulk(2, 2.5ulk) == 5);
+  assert(muliulk(10, 0.5ulk) == 5);
+
+  // Fractional result is missing and value truncates towards zero
+  assert(muliulk(3, 2.5ulk) == 7);
+  assert(muliulk(15, 0.5ulk) == 7);
+
+  // Limited resulution of the _Accum fractional bits does not always allow for
+  // the most precise values.
+  // 1 * unsigned long _Accum limits
+  assert(muliulk(1, 4294967295.99999999999ulk) == 4294967295);
+
+  // unsigned long _Accum limits as integer * near 1 long _Accum (evenly divisibly)
+  assert(muliulk(4294967295, 0.99999999999ulk) == 4294967294);
+
+  // unsigned long int max * near 1 unsigned long _Accum
+  assert(muliulk(18446744073709551615, 0.99999999999ulk) == 18446744069414584319);
+
+  // unsigned long int max * 1 unsigned long _Accum (exact values)
+  assert(muliulk(18446744073709551615, 1.0ulk) == 18446744073709551615);
+
+  return 0;
+}
Index: test/Frontend/fixed_point_all_conversions.c
===================================================================
--- test/Frontend/fixed_point_all_conversions.c
+++ test/Frontend/fixed_point_all_conversions.c
@@ -72,3 +72,15 @@
 CONVERT_FIXED_POINT_TYPE(short _Accum, ShortAccum);
 CONVERT_FIXED_POINT_TYPE(_Accum, Accum);
 CONVERT_FIXED_POINT_TYPE(long _Accum, LongAccum);
+
+#define assert(b) \
+  if (!(b)) {     \
+    return 1;     \
+  }
+
+int main() {
+  unsigned _Fract f = 0.75ur;
+  long _Accum a = 0.75lk;
+  assert(UnsignedFractType_to_LongAccum(f) == a);
+  return 0;
+}
Index: lib/Parse/Parser.cpp
===================================================================
--- lib/Parse/Parser.cpp
+++ lib/Parse/Parser.cpp
@@ -674,6 +674,9 @@
   case tok::annot_pragma_fp_contract:
     HandlePragmaFPContract();
     return nullptr;
+  case tok::annot_pragma_fx_full_precision:
+    HandlePragmaFXFullPrecision();
+    return nullptr;
   case tok::annot_pragma_fp:
     HandlePragmaFP();
     break;
Index: lib/Parse/ParseStmt.cpp
===================================================================
--- lib/Parse/ParseStmt.cpp
+++ lib/Parse/ParseStmt.cpp
@@ -337,6 +337,7 @@
     return StmtEmpty();
 
   case tok::annot_pragma_fp_contract:
+  case tok::annot_pragma_fx_full_precision:
     ProhibitAttributes(Attrs);
     Diag(Tok, diag::err_pragma_fp_contract_scope);
     ConsumeAnnotationToken();
@@ -899,6 +900,9 @@
     case tok::annot_pragma_fp_contract:
       HandlePragmaFPContract();
       break;
+    case tok::annot_pragma_fx_full_precision:
+      HandlePragmaFXFullPrecision();
+      break;
     case tok::annot_pragma_fp:
       HandlePragmaFP();
       break;
Index: lib/Parse/ParsePragma.cpp
===================================================================
--- lib/Parse/ParsePragma.cpp
+++ lib/Parse/ParsePragma.cpp
@@ -122,6 +122,14 @@
   }
 };
 
+/// PragmaSTDC_FX_FULL_PRECISIONHandler - "\#pragma STDC FX_FULL_PRECISION ...".
+struct PragmaSTDC_FX_FULL_PRECISIONHandler : public PragmaHandler {
+  PragmaSTDC_FX_FULL_PRECISIONHandler() : PragmaHandler("FX_FULL_PRECISION") {}
+
+  void HandlePragma(Preprocessor &PP, PragmaIntroducerKind Introducer,
+                    Token &Tok) override;
+};
+
 /// PragmaSTDC_UnknownHandler - "\#pragma STDC ...".
 struct PragmaSTDC_UnknownHandler : public PragmaHandler {
   PragmaSTDC_UnknownHandler() = default;
@@ -283,6 +291,9 @@
   STDCCXLIMITHandler.reset(new PragmaSTDC_CX_LIMITED_RANGEHandler());
   PP.AddPragmaHandler("STDC", STDCCXLIMITHandler.get());
 
+  STDCFXPRECHandler.reset(new PragmaSTDC_FX_FULL_PRECISIONHandler());
+  PP.AddPragmaHandler("STDC", STDCFXPRECHandler.get());
+
   STDCUnknownHandler.reset(new PragmaSTDC_UnknownHandler());
   PP.AddPragmaHandler("STDC", STDCUnknownHandler.get());
 
@@ -436,6 +447,9 @@
   PP.RemovePragmaHandler("STDC", STDCCXLIMITHandler.get());
   STDCCXLIMITHandler.reset();
 
+  PP.RemovePragmaHandler("STDC", STDCFXPRECHandler.get());
+  STDCFXPRECHandler.reset();
+
   PP.RemovePragmaHandler("STDC", STDCUnknownHandler.get());
   STDCUnknownHandler.reset();
 
@@ -591,6 +605,12 @@
   ConsumeAnnotationToken();
 }
 
+// TODO: Follow logic similar to FPContract for handling
+void Parser::HandlePragmaFXFullPrecision() {
+  assert(Tok.is(tok::annot_pragma_fx_full_precision));
+  ConsumeAnnotationToken();
+}
+
 StmtResult Parser::HandlePragmaCaptured()
 {
   assert(Tok.is(tok::annot_pragma_captured));
@@ -2033,6 +2053,22 @@
   PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true);
 }
 
+void PragmaSTDC_FX_FULL_PRECISIONHandler::HandlePragma(
+    Preprocessor &PP, PragmaIntroducerKind Introducer, Token &Tok) {
+  tok::OnOffSwitch OOS;
+  if (PP.LexOnOffSwitch(OOS)) return;
+
+  MutableArrayRef<Token> Toks(PP.getPreprocessorAllocator().Allocate<Token>(1),
+                              1);
+  Toks[0].startToken();
+  Toks[0].setKind(tok::annot_pragma_fx_full_precision);
+  Toks[0].setLocation(Tok.getLocation());
+  Toks[0].setAnnotationEndLoc(Tok.getLocation());
+  Toks[0].setAnnotationValue(
+      reinterpret_cast<void *>(static_cast<uintptr_t>(OOS)));
+  PP.EnterTokenStream(Toks, /*DisableMacroExpansion=*/true);
+}
+
 void 
 PragmaOpenCLExtensionHandler::HandlePragma(Preprocessor &PP, 
                                            PragmaIntroducerKind Introducer,
Index: lib/CodeGen/CodeGenFunction.h
===================================================================
--- lib/CodeGen/CodeGenFunction.h
+++ lib/CodeGen/CodeGenFunction.h
@@ -3648,6 +3648,11 @@
   RValue EmitNVPTXDevicePrintfCallExpr(const CallExpr *E,
                                        ReturnValueSlot ReturnValue);
 
+  Address CreateAddr(llvm::Type *Ty);
+  RValue EmitMuliFX(const CallExpr *E);
+  llvm::Value *EmitLogNFXIntrinsic(const CallExpr *E, unsigned base);
+  llvm::Value *EmitPow10FXIntrinsic(const CallExpr *E);
+
   RValue EmitBuiltinExpr(const FunctionDecl *FD,
                          unsigned BuiltinID, const CallExpr *E,
                          ReturnValueSlot ReturnValue);
Index: lib/CodeGen/CGExprScalar.cpp
===================================================================
--- lib/CodeGen/CGExprScalar.cpp
+++ lib/CodeGen/CGExprScalar.cpp
@@ -1074,31 +1074,23 @@
 
   Value *Res = Src;
 
-  // Casting between fixed point types involves separating the integral and
-  // fractional bits, potentially shifting them, then joining back together.
   unsigned dest_fbits = CGF.getContext().getFixedPointScale(DstTy);
   unsigned src_fbits = CGF.getContext().getFixedPointScale(SrcTy);
-  unsigned dest_ibits = CGF.getContext().getFixedPointIBits(DstTy);
-  unsigned src_ibits = CGF.getContext().getFixedPointIBits(SrcTy);
+  unsigned dest_width = CGF.getContext().getTypeSize(DstTy);
+  unsigned src_width = CGF.getContext().getTypeSize(SrcTy);
+  bool src_signed = SrcTy->isSignedFixedPointType();
 
-  // If the number of integral bits is decreasing, trim off any extra bits while
-  // retaining the sign.
-  if (dest_ibits < src_ibits) {
-    Res = Builder.CreateShl(Res, src_ibits - dest_ibits);
-    Res = Builder.CreateAShr(Res, src_ibits - dest_ibits);
-  }
-
-  // Move the radix. For irrational numbers, there will be loss of precision
-  // using this method when the number of fbits increases since we will be right
-  // padding zeros. Precision can still be retained if we temporarily convert to
-  // a float and perform some floating point arithmetic, though this may cost
-  // more. Enable that if #pragma FX_FULL_PRECISION is provided.
   if (dest_fbits > src_fbits) {
+    llvm::Type *NewTy = Builder.getIntNTy(src_width + dest_fbits - src_fbits);
+    Res = Builder.CreateIntCast(Res, NewTy, src_signed);
     Res = Builder.CreateShl(Res, dest_fbits - src_fbits);
-  } else if (dest_fbits < src_fbits) {
-    Res = Builder.CreateAShr(Res, src_fbits - dest_fbits);
+  } else {
+    Res = src_signed ? Builder.CreateAShr(Res, src_fbits - dest_fbits)
+                     : Builder.CreateLShr(Res, src_fbits - dest_fbits);
   }
-  return Res;
+
+  llvm::Type *NewTy = Builder.getIntNTy(dest_width);
+  return Builder.CreateIntCast(Res, NewTy, src_signed);
 }
 
 /// Emit a conversion from the specified type to the specified destination type,
@@ -1155,11 +1147,11 @@
     }
   }
 
-  bool WorkingOnFixedPoints =
-      DstType->isFixedPointType() && SrcType->isFixedPointType();
+  if (DstType->isFixedPointType() && SrcType->isFixedPointType())
+    return EmitFixedPointRadixShift(Src, SrcType, DstType);
 
-  // Ignore conversions like int -> uint, unless they're fixed point types.
-  if (SrcTy == DstTy && !WorkingOnFixedPoints)
+  // Ignore conversions like int -> uint
+  if (SrcTy == DstTy)
     return Src;
 
   // Handle pointer conversions next: pointers can only be converted to/from
@@ -1263,18 +1255,9 @@
     DstTy = CGF.FloatTy;
   }
 
-  int order = WorkingOnFixedPoints
-                  ? CGF.getContext().getFixedPointTypeOrder(DstType, SrcType)
-                  : 0;
-
-  if (WorkingOnFixedPoints && order < 0) {
-    // Casting down, so we will need to shift early as to not lose data
-    Src = EmitFixedPointRadixShift(Src, SrcType, DstType);
-  }
-
   if (isa<llvm::IntegerType>(SrcTy)) {
     bool InputSigned = (SrcType->isSignedIntegerOrEnumerationType() ||
-                        SrcType->isFixedPointType());
+                        SrcType->isSignedFixedPointType());
     if (SrcType->isBooleanType() && TreatBooleanAsSigned) {
       InputSigned = true;
     }
@@ -1299,11 +1282,6 @@
       Res = Builder.CreateFPExt(Src, DstTy, "conv");
   }
 
-  if (WorkingOnFixedPoints && order >= 0) {
-    // Casting up (or same type), so we can safely shift without losing data
-    Res = EmitFixedPointRadixShift(Res, SrcType, DstType);
-  }
-
   if (DstTy != ResTy) {
     if (CGF.getContext().getTargetInfo().useFP16ConversionIntrinsics()) {
       assert(ResTy->isIntegerTy(16) && "Only half FP requires extra conversion");
@@ -2068,7 +2046,8 @@
     Val = EmitScalarConversion(Val, E->getType(), DestTy, CE->getExprLoc());
 
     return Builder.CreateFDiv(
-        Val, llvm::ConstantFP::get(CGF.CGM.FloatTy, (1ULL << scale) * 1.0));
+        Val, llvm::ConstantFP::get(CGF.ConvertTypeForMem(DestTy),
+                                   (1ULL << scale) * 1.0));
   }
 
   case CK_IntegralCast:
Index: lib/CodeGen/CGBuiltin.cpp
===================================================================
--- lib/CodeGen/CGBuiltin.cpp
+++ lib/CodeGen/CGBuiltin.cpp
@@ -1252,6 +1252,114 @@
   return Res;
 }
 
+RValue CodeGenFunction::EmitMuliFX(const CallExpr *E) {
+  const Expr *LHSExpr = E->getArg(0);
+  const Expr *RHSExpr = E->getArg(1);
+  const QualType &LHSTy = LHSExpr->getType();
+  const QualType &RHSTy = RHSExpr->getType();
+  assert(LHSTy->isIntegralType(getContext()));
+  assert(RHSTy->isFixedPointType() && !RHSTy->isSaturatedFixedPointType());
+  assert(LHSTy->isSignedIntegerType() == RHSTy->isSignedFixedPointType());
+
+  // Cast up then cast down back to an int
+  unsigned LHSWidth = getContext().getTypeInfo(LHSTy).Width;
+  unsigned RHSWidth = getContext().getTypeInfo(RHSTy).Width;
+  unsigned BufferWidth = LHSWidth + RHSWidth;
+  llvm::Type *ResultTy = Builder.getIntNTy(BufferWidth);
+  unsigned Scale = getContext().getFixedPointScale(RHSTy);
+  bool isSigned = LHSTy->isSignedIntegerType();
+
+  llvm::Value *LHS = EmitScalarExpr(LHSExpr);
+  llvm::Value *RHS = EmitScalarExpr(RHSExpr);
+
+  LHS = Builder.CreateIntCast(LHS, ResultTy, isSigned);
+  RHS = Builder.CreateIntCast(RHS, ResultTy, isSigned);
+
+  llvm::Value *Result = Builder.CreateMul(LHS, RHS);
+  Result = Builder.CreateAShr(Result, Scale);
+
+  // Special case for multiplying by -1 and -1 with _Fracts
+  if (RHSTy->isFractFixedPointType() && isSigned) {
+    // TODO: Not sure if I can just make -1 as second argument since it takes a
+    // uint64_t.
+    llvm::APInt LHSOne(BufferWidth, 0, /*isSigned=*/true);
+    --LHSOne;
+
+    llvm::Value *LHSIsMinusOne =
+        Builder.CreateICmpEQ(LHS, Builder.getInt(LHSOne), "LHS is -1");
+
+    // Will need to mask the _Fract to check if -1
+    uint64_t Mask = (1ULL << (Scale + 1)) - 1;
+    uint64_t RHSOne = 1ULL << Scale;
+    llvm::Value *MaskedRHS = Builder.CreateAnd(RHS, Mask);
+    llvm::Value *RHSIsMinusOne = Builder.CreateICmpEQ(
+        MaskedRHS, Builder.getIntN(BufferWidth, RHSOne), "RHS is -1");
+
+    Result =
+        Builder.CreateSelect(Builder.CreateAnd(LHSIsMinusOne, RHSIsMinusOne),
+                             Builder.getIntN(BufferWidth, 1), Result);
+  }
+
+  Result = Builder.CreateIntCast(Result, getTypes().ConvertTypeForMem(LHSTy),
+                                 isSigned);
+
+  return RValue::get(Result);
+}
+
+llvm::Value *CodeGenFunction::EmitPow10FXIntrinsic(const CallExpr *E) {
+  const Expr *Arg = E->getArg(0);
+  const QualType &ArgTy = Arg->getType();
+  const QualType &ReturnTy = E->getCallReturnType(getContext());
+  assert(ArgTy->isSignedFixedPointType());
+  assert(ReturnTy->isSignedFixedPointType());
+
+  Value *ArgVal = EmitScalarExpr(Arg);
+
+  // FIXME: Hardcoded function type for __pow10fx in compiler-rt
+  // The scale is also hardcoded as 31, the default scale of a long _Accum.
+  std::string FuncName = "__pow10fx";
+  llvm::FunctionType *FuncType =
+      llvm::FunctionType::get(Builder.getInt64Ty(), {Builder.getInt64Ty()},
+                              /*isVarArg=*/false);
+  Function *F =
+      cast<Function>(CGM.getModule().getOrInsertFunction(FuncName, FuncType));
+
+  return Builder.CreateCall(F, {ArgVal});
+}
+
+llvm::Value *CodeGenFunction::EmitLogNFXIntrinsic(const CallExpr *E,
+                                                  unsigned base) {
+  const Expr *Arg = E->getArg(0);
+  const QualType &ArgTy = Arg->getType();
+  const QualType &ReturnTy = E->getCallReturnType(getContext());
+  assert(ArgTy->isUnsignedFixedPointType());
+  assert(ReturnTy->isSignedFixedPointType());
+
+  unsigned SrcScale = getContext().getFixedPointScale(ArgTy);
+  unsigned DstScale = getContext().getFixedPointScale(ReturnTy);
+
+  Value *ArgVal = EmitScalarExpr(Arg);
+  Value *Precision = ConstantInt::get(Builder.getInt32Ty(), SrcScale);
+  Value *DstPrecision = ConstantInt::get(Builder.getInt32Ty(), DstScale);
+  Value *Base = ConstantInt::get(Builder.getInt32Ty(), base);
+
+  // FIXME: Hardcoded function type for __logNScaledInt in compiler-rt
+  std::string FuncName = "__logNScaledInt";
+  llvm::FunctionType *FuncType = llvm::FunctionType::get(
+      Builder.getInt64Ty(),
+      {Builder.getInt64Ty(), Builder.getInt32Ty(), Builder.getInt32Ty(), Builder.getInt32Ty()},
+      /*isVarArg=*/false);
+  Function *F = cast<Function>(CGM.getModule().getOrInsertFunction(FuncName, FuncType));
+
+  return Builder.CreateCall(F, {ArgVal, Precision, DstPrecision, Base});
+}
+
+Address CodeGenFunction::CreateAddr(llvm::Type *Ty) {
+  Value *ValAlloc = Builder.CreateAlloca(Ty);
+  unsigned ValAlign = ValAlloc->getPointerAlignment(CGM.getDataLayout());
+  return Address(ValAlloc, CharUnits::fromQuantity(ValAlign));
+}
+
 RValue CodeGenFunction::EmitBuiltinExpr(const FunctionDecl *FD,
                                         unsigned BuiltinID, const CallExpr *E,
                                         ReturnValueSlot ReturnValue) {
@@ -1456,6 +1564,23 @@
 
   switch (BuiltinID) {
   default: break;
+  case Builtin::BIpow10fx:
+    return RValue::get(EmitPow10FXIntrinsic(E));
+  case Builtin::BIlog2fx:
+    return RValue::get(EmitLogNFXIntrinsic(E, 2));
+  case Builtin::BIlog10fx:
+    return RValue::get(EmitLogNFXIntrinsic(E, 10));
+
+  case Builtin::BImulir:
+  case Builtin::BImulilr:
+  case Builtin::BImulik:
+  case Builtin::BImulilk:
+  case Builtin::BImuliur:
+  case Builtin::BImuliulr:
+  case Builtin::BImuliuk:
+  case Builtin::BImuliulk:
+    return EmitMuliFX(E);
+
   case Builtin::BI__builtin___CFStringMakeConstantString:
   case Builtin::BI__builtin___NSStringMakeConstantString:
     return RValue::get(ConstantEmitter(*this).emitAbstract(E, E->getType()));
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -9288,6 +9288,20 @@
     else
       Type = Unsigned ? Context.UnsignedIntTy : Context.IntTy;
     break;
+  case 'k':
+    assert(HowLong <= 1 && "_Accum can be at most long");
+    if (HowLong == 1)
+      Type = Unsigned ? Context.UnsignedLongAccumTy : Context.LongAccumTy;
+    else
+      Type = Unsigned ? Context.UnsignedAccumTy : Context.AccumTy;
+    break;
+  case 'r':
+    assert(HowLong <= 1 && "_Fract can be at most long");
+    if (HowLong == 1)
+      Type = Unsigned ? Context.UnsignedLongFractTy : Context.LongFractTy;
+    else
+      Type = Unsigned ? Context.UnsignedFractTy : Context.FractTy;
+    break;
   case 'c':
     assert(HowLong == 0 && "Bad modifiers used with 'c'!");
     if (Signed)
Index: include/clang/Parse/Parser.h
===================================================================
--- include/clang/Parse/Parser.h
+++ include/clang/Parse/Parser.h
@@ -188,6 +188,7 @@
   std::unique_ptr<PragmaHandler> FPHandler;
   std::unique_ptr<PragmaHandler> STDCFENVHandler;
   std::unique_ptr<PragmaHandler> STDCCXLIMITHandler;
+  std::unique_ptr<PragmaHandler> STDCFXPRECHandler;
   std::unique_ptr<PragmaHandler> STDCUnknownHandler;
   std::unique_ptr<PragmaHandler> AttributePragmaHandler;
 
@@ -667,6 +668,10 @@
   /// #pragma STDC FP_CONTRACT...
   void HandlePragmaFPContract();
 
+  /// Handle the annotation token produced for
+  /// #pragma STDC FX_FULL_PRECISION...
+  void HandlePragmaFXFullPrecision();
+
   /// Handle the annotation token produced for
   /// #pragma clang fp ...
   void HandlePragmaFP();
Index: include/clang/Basic/TokenKinds.def
===================================================================
--- include/clang/Basic/TokenKinds.def
+++ include/clang/Basic/TokenKinds.def
@@ -779,6 +779,11 @@
 // handles them.
 ANNOTATION(pragma_fp_contract)
 
+// Annotation for #pragma STDC FX_FULL_PRECISION...
+// The lexer produces these so that they only take effect when the parser
+// handles them.
+ANNOTATION(pragma_fx_full_precision)
+
 // Annotation for #pragma pointers_to_members...
 // The lexer produces these so that they only take effect when the parser
 // handles them.
Index: include/clang/Basic/Builtins.def
===================================================================
--- include/clang/Basic/Builtins.def
+++ include/clang/Basic/Builtins.def
@@ -45,6 +45,8 @@
 //  SJ -> sigjmp_buf
 //  K -> ucontext_t
 //  p -> pid_t
+//  r -> _Fract
+//  k -> _Accum
 //  . -> "...".  This may only occur at the end of the function list.
 //
 // Types may be prefixed with the following modifiers:
@@ -1362,6 +1364,22 @@
 LIBBUILTIN(_Block_object_dispose, "vvC*iC", "f", "Blocks.h", ALL_LANGUAGES)
 // FIXME: Also declare NSConcreteGlobalBlock and NSConcreteStackBlock.
 
+// ISO/IEC JTC1 SC22 WG14 N1169
+LIBBUILTIN(mulir, "iir", "f", "stdfix.h", C_LANG)
+LIBBUILTIN(mulilr, "LiLiLr", "f", "stdfix.h", C_LANG)
+LIBBUILTIN(mulik, "iik", "f", "stdfix.h", C_LANG)
+LIBBUILTIN(mulilk, "LiLiLk", "f", "stdfix.h", C_LANG)
+
+LIBBUILTIN(muliur, "UiUiUr", "f", "stdfix.h", C_LANG)
+LIBBUILTIN(muliulr, "ULiULiULr", "f", "stdfix.h", C_LANG)
+LIBBUILTIN(muliuk, "UiUiUk", "f", "stdfix.h", C_LANG)
+LIBBUILTIN(muliulk, "ULiULiULk", "f", "stdfix.h", C_LANG)
+
+// Not part of N1169 but requested
+LIBBUILTIN(pow10fx, "LkLk", "f", "stdfix.h", C_LANG)
+LIBBUILTIN(log2fx, "LkULk", "f", "stdfix.h", C_LANG)
+LIBBUILTIN(log10fx, "LkULk", "f", "stdfix.h", C_LANG)
+
 // Annotation function
 BUILTIN(__builtin_annotation, "v.", "tn")
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to