[llvm-commits] [dragonegg] r154663 - in /dragonegg/trunk: src/Convert.cpp test/validator/c++/2012-04-13-EnumRange.cpp

Duncan Sands baldrick at free.fr
Fri Apr 13 04:14:03 PDT 2012


Author: baldrick
Date: Fri Apr 13 06:14:03 2012
New Revision: 154663

URL: http://llvm.org/viewvc/llvm-project?rev=154663&view=rev
Log:
When compiling C++ with -fstrict-enums the enum size is not visible
in the type precision, only in TYPE_MIN_VALUE and TYPE_MAX_VALUE, so
compute type ranges from them rather than from the precision.

Added:
    dragonegg/trunk/test/validator/c++/2012-04-13-EnumRange.cpp
Modified:
    dragonegg/trunk/src/Convert.cpp

Modified: dragonegg/trunk/src/Convert.cpp
URL: http://llvm.org/viewvc/llvm-project/dragonegg/trunk/src/Convert.cpp?rev=154663&r1=154662&r2=154663&view=diff
==============================================================================
--- dragonegg/trunk/src/Convert.cpp (original)
+++ dragonegg/trunk/src/Convert.cpp Fri Apr 13 06:14:03 2012
@@ -291,27 +291,41 @@
   llvm_unreachable("Don't know how to turn this into memory!");
 }
 
-/// describeTypeRange - Given two integer types, return metadata describing the
-/// set obtained by extending all values of the smaller type to the larger.
-static MDNode *describeTypeRange(Type *SmallTy, Type *LargeTy, bool isSigned) {
-  assert(isa<IntegerType>(SmallTy) && isa<IntegerType>(LargeTy) &&
-         "Expected integer types!");
-  unsigned ActiveBits = SmallTy->getIntegerBitWidth();
-  unsigned TotalBits = LargeTy->getIntegerBitWidth();
-  assert(ActiveBits < TotalBits && "Full range not allowed!");
-  assert(ActiveBits > 0 && "Need at least one bit!");
-  APInt First, Last;
-  if (isSigned) {
-    Last = APInt::getOneBitSet(TotalBits, ActiveBits - 1);
-    First = -Last;
-  } else {
-    First = APInt::getNullValue(TotalBits);
-    Last = APInt::getOneBitSet(TotalBits, ActiveBits);
-  }
+/// describeTypeRange - Return metadata describing the set of possible values
+/// that an in-memory variable of the given GCC type can take on.
+static MDNode *describeTypeRange(tree type) {
+  if (!INTEGRAL_TYPE_P(type)) return 0; // Only discrete types have ranges.
+
+  // The range of possible values is TYPE_MIN_VALUE .. TYPE_MAX_VALUE.
+  tree min = TYPE_MIN_VALUE(type);
+  assert(min && TREE_CODE(min) == INTEGER_CST && "Min not a constant!");
+  tree max = TYPE_MAX_VALUE(type);
+  assert(max && TREE_CODE(max) == INTEGER_CST && "Max not a constant!");
+
+  unsigned BitWidth = GET_MODE_BITSIZE(TYPE_MODE(type));
+
+  APInt Lo = getIntegerValue(min);
+  assert(Lo.getBitWidth() <= BitWidth && "Min value doesn't fit in type!");
+  if (Lo.getBitWidth() != BitWidth)
+    Lo = TYPE_UNSIGNED(TREE_TYPE(min)) ?
+      Lo.zext(BitWidth) : Lo.sext(BitWidth);
+
+  APInt Hi = getIntegerValue(max);
+  assert(Hi.getBitWidth() <= BitWidth && "Max value doesn't fit in type!");
+  if (Hi.getBitWidth() != BitWidth)
+    Hi = TYPE_UNSIGNED(TREE_TYPE(max)) ?
+      Hi.zext(BitWidth) : Hi.sext(BitWidth);
 
-  Value *Range[2] = {
-    ConstantInt::get(LargeTy, First), ConstantInt::get(LargeTy, Last)
-  };
+  // Unlike GCC's, LLVM ranges do not include the upper end point.
+  ++Hi;
+
+  // If the range is everything then it is useless.
+  if (Hi == Lo)
+    return 0;
+
+  // Return the range [Lo, Hi).
+  Type *Ty = IntegerType::get(Context, BitWidth);
+  Value *Range[2] = { ConstantInt::get(Ty, Lo), ConstantInt::get(Ty, Hi) };
   return MDNode::get(Context, Range);
 }
 
@@ -379,8 +393,13 @@
 
   // If loading the register type directly out of memory gives the right result,
   // then just do that.
-  if (isDirectMemoryAccessSafe(RegTy, type))
-    return LoadFromLocation(Loc, RegTy, AliasTag, Builder);
+  if (isDirectMemoryAccessSafe(RegTy, type)) {
+    LoadInst *LI = LoadFromLocation(Loc, RegTy, AliasTag, Builder);
+    MDNode *Range = describeTypeRange(type);
+    if (Range)
+      LI->setMetadata(LLVMContext::MD_range, Range);
+    return LI;
+  }
 
   // There is a discrepancy between the in-register type and the in-memory type.
   switch (TREE_CODE(type)) {
@@ -399,8 +418,9 @@
     unsigned Size = GET_MODE_BITSIZE(TYPE_MODE(type));
     Type *MemTy = IntegerType::get(Context, Size);
     LoadInst *LI = LoadFromLocation(Loc, MemTy, AliasTag, Builder);
-    MDNode *Range = describeTypeRange(RegTy, MemTy, !TYPE_UNSIGNED(type));
-    LI->setMetadata(LLVMContext::MD_range, Range);
+    MDNode *Range = describeTypeRange(type);
+    if (Range)
+      LI->setMetadata(LLVMContext::MD_range, Range);
     return Builder.CreateTruncOrBitCast(LI, RegTy);
   }
 

Added: dragonegg/trunk/test/validator/c++/2012-04-13-EnumRange.cpp
URL: http://llvm.org/viewvc/llvm-project/dragonegg/trunk/test/validator/c%2B%2B/2012-04-13-EnumRange.cpp?rev=154663&view=auto
==============================================================================
--- dragonegg/trunk/test/validator/c++/2012-04-13-EnumRange.cpp (added)
+++ dragonegg/trunk/test/validator/c++/2012-04-13-EnumRange.cpp Fri Apr 13 06:14:03 2012
@@ -0,0 +1,9 @@
+// RUN: %dragonegg -fstrict-enums -S -o - %s | FileCheck %s
+
+enum A { alpha, beta } a;
+
+int foo() {
+  return a;
+// CHECK: load i32 @a,{{.*}} !range !0
+// CHECK: !0 = metadata !{i32 0, i32 2}
+}





More information about the llvm-commits mailing list