[llvm-commits] [dragonegg] r127001 - /dragonegg/trunk/llvm-convert.cpp

Duncan Sands baldrick at free.fr
Fri Mar 4 08:18:42 PST 2011


Author: baldrick
Date: Fri Mar  4 10:18:42 2011
New Revision: 127001

URL: http://llvm.org/viewvc/llvm-project?rev=127001&view=rev
Log:
Rewrite conversion of REAL_CST expressions using GCC's native_encode_expr.
This makes the logic completely uniform, so it also works for __float128
(or at least it would if we converted it into fp128 - but we are not yet
ready for this).

Modified:
    dragonegg/trunk/llvm-convert.cpp

Modified: dragonegg/trunk/llvm-convert.cpp
URL: http://llvm.org/viewvc/llvm-project/dragonegg/trunk/llvm-convert.cpp?rev=127001&r1=127000&r2=127001&view=diff
==============================================================================
--- dragonegg/trunk/llvm-convert.cpp (original)
+++ dragonegg/trunk/llvm-convert.cpp Fri Mar  4 10:18:42 2011
@@ -7918,6 +7918,21 @@
   }
 }
 
+/// EncodeExpr - Write the given expression into Buffer as it would appear in
+/// memory on the target (the buffer is resized to contain exactly the bytes
+/// written).  Return the number of bytes written; this can also be obtained
+/// by querying the buffer's size.
+/// The following kinds of expressions are currently supported: INTEGER_CST,
+/// REAL_CST, COMPLEX_CST, VECTOR_CST, STRING_CST.
+static unsigned EncodeExpr(tree exp, SmallVectorImpl<unsigned char> &Buffer) {
+  const tree type = TREE_TYPE(exp);
+  unsigned SizeInBytes = (TREE_INT_CST_LOW(TYPE_SIZE(type)) + 7) / 8;
+  Buffer.resize(SizeInBytes);
+  unsigned BytesWritten = native_encode_expr(exp, &Buffer[0], SizeInBytes);
+  assert(BytesWritten == SizeInBytes && "Failed to fully encode expression!");
+  return BytesWritten;
+}
+
 Constant *TreeConstantToLLVM::ConvertINTEGER_CST(tree exp) {
   const Type *Ty = ConvertType(TREE_TYPE(exp));
 
@@ -7944,61 +7959,35 @@
 }
 
 Constant *TreeConstantToLLVM::ConvertREAL_CST(tree exp) {
-  const Type *Ty = ConvertType(TREE_TYPE(exp));
-  assert(Ty->isFloatingPointTy() && "Integer REAL_CST?");
-  long RealArr[2];
-  union {
-    int UArr[2];
-    double V;
-  };
-  if (Ty->isFloatTy() || Ty->isDoubleTy()) {
-    REAL_VALUE_TO_TARGET_DOUBLE(TREE_REAL_CST(exp), RealArr);
-
-    // Here's how this works:
-    // REAL_VALUE_TO_TARGET_DOUBLE() will generate the floating point number
-    // as an array of integers in the target's representation.  Each integer
-    // in the array will hold 32 bits of the result REGARDLESS OF THE HOST'S
-    // INTEGER SIZE.
-    //
-    // This, then, makes the conversion pretty simple.  The tricky part is
-    // getting the byte ordering correct and make sure you don't print any
-    // more than 32 bits per integer on platforms with ints > 32 bits.
-    //
-    // We want to switch the words of UArr if host and target endianness
-    // do not match.  FLOAT_WORDS_BIG_ENDIAN describes the target endianness.
-    // The host's used to be available in HOST_WORDS_BIG_ENDIAN, but the gcc
-    // maintainers removed this in a fit of cleanliness between 4.0
-    // and 4.2. llvm::sys has a substitute.
-
-    UArr[0] = RealArr[0];   // Long -> int convert
-    UArr[1] = RealArr[1];
-
-    if (llvm::sys::isBigEndianHost() != FLOAT_WORDS_BIG_ENDIAN)
-      std::swap(UArr[0], UArr[1]);
-
-    return ConstantFP::get(Context, Ty->isFloatTy() ?
-                           APFloat((float)V) : APFloat(V));
-  } else if (Ty->isX86_FP80Ty()) {
-    long RealArr[4];
-    uint64_t UArr[2];
-    REAL_VALUE_TO_TARGET_LONG_DOUBLE(TREE_REAL_CST(exp), RealArr);
-    UArr[0] = ((uint64_t)((uint32_t)RealArr[0])) |
-              ((uint64_t)((uint32_t)RealArr[1]) << 32);
-    UArr[1] = (uint16_t)RealArr[2];
-    return ConstantFP::get(Context, APFloat(APInt(80, 2, UArr)));
-  } else if (Ty->isPPC_FP128Ty()) {
-    long RealArr[4];
-    uint64_t UArr[2];
-    REAL_VALUE_TO_TARGET_LONG_DOUBLE(TREE_REAL_CST(exp), RealArr);
-
-    UArr[0] = ((uint64_t)((uint32_t)RealArr[0]) << 32) |
-              ((uint64_t)((uint32_t)RealArr[1]));
-    UArr[1] = ((uint64_t)((uint32_t)RealArr[2]) << 32) |
-              ((uint64_t)((uint32_t)RealArr[3]));
-    return ConstantFP::get(Context, APFloat(APInt(128, 2, UArr)));
-  }
-  assert(0 && "Floating point type not handled yet");
-  return 0;   // outwit compiler warning
+  // Encode the constant in Buffer in target format.
+  SmallVector<unsigned char, 16> Buffer;
+  EncodeExpr(exp, Buffer);
+
+  // Ensure that the value is always stored little-endian wise, as we are going
+  // to make an APInt out of it, and APInts are always little-endian.
+  unsigned Precision = TYPE_PRECISION(TREE_TYPE(exp));
+  if (FLOAT_WORDS_BIG_ENDIAN)
+    std::reverse(Buffer.begin(), Buffer.begin() + (Precision + 7) / 8);
+
+  // We are going to view the buffer as an array of APInt words.  Ensure that
+  // the buffer contains a whole number of words by extending it if necessary.
+  unsigned Words = (Buffer.size() * 8 + integerPartWidth - 1)/integerPartWidth;
+  Buffer.resize(Words * (integerPartWidth / 8));
+  integerPart *Parts = (integerPart *)&Buffer[0];
+
+  bool isPPC_FP128 = ConvertType(TREE_TYPE(exp))->isPPC_FP128Ty();
+  if (isPPC_FP128) {
+    // This type is actually a pair of doubles in disguise.  They turn up the
+    // wrong way round here, so flip them.
+    assert(FLOAT_WORDS_BIG_ENDIAN && "PPC not big endian!");
+    assert(Words == 2 && Precision == 128 && "Strange size for PPC_FP128!");
+    std::swap(Parts[0], Parts[1]);
+  }
+
+  // Form an APInt from the buffer, an APFloat from the APInt, and the desired
+  // floating point constant from the APFloat, phew!
+  const APInt &I = APInt(Precision, Words, Parts);
+  return ConstantFP::get(Context, APFloat(I, !isPPC_FP128));
 }
 
 Constant *TreeConstantToLLVM::ConvertVECTOR_CST(tree exp) {





More information about the llvm-commits mailing list