[llvm-commits] [llvm] r156704 - in /llvm/trunk: include/llvm/Instructions.h include/llvm/Support/ConstantRangesSet.h lib/Bitcode/Reader/BitcodeReader.cpp lib/Bitcode/Writer/BitcodeWriter.cpp lib/VMCore/Instructions.cpp test/Bitcode/2012-05-07-SwitchInstRangesSupport.ll

Stepan Dyatkovskiy stpworld at narod.ru
Sat May 12 03:48:17 PDT 2012


Author: dyatkovskiy
Date: Sat May 12 05:48:17 2012
New Revision: 156704

URL: http://llvm.org/viewvc/llvm-project?rev=156704&view=rev
Log:
Recommited r156374 with critical fixes in BitcodeReader/Writer:
Ordinary patch for PR1255.
Added new case-ranges orientated methods for adding/removing cases in SwitchInst. After this patch cases will internally representated as ConstantArray-s instead of ConstantInt, externally cases wrapped within the ConstantRangesSet object.
Old methods of SwitchInst are also works well, but marked as deprecated. So on this stage we have no side effects except that I added support for case ranges in BitcodeReader/Writer, of course test for Bitcode is also added. Old "switch" format is also supported.


Added:
    llvm/trunk/test/Bitcode/2012-05-07-SwitchInstRangesSupport.ll
Modified:
    llvm/trunk/include/llvm/Instructions.h
    llvm/trunk/include/llvm/Support/ConstantRangesSet.h
    llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp
    llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp
    llvm/trunk/lib/VMCore/Instructions.cpp

Modified: llvm/trunk/include/llvm/Instructions.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Instructions.h?rev=156704&r1=156703&r2=156704&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Instructions.h (original)
+++ llvm/trunk/include/llvm/Instructions.h Sat May 12 05:48:17 2012
@@ -20,6 +20,8 @@
 #include "llvm/DerivedTypes.h"
 #include "llvm/Attributes.h"
 #include "llvm/CallingConv.h"
+#include "llvm/Support/ConstantRangesSet.h"
+#include "llvm/Support/CRSBuilder.h"
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/Support/ErrorHandling.h"
@@ -2500,9 +2502,19 @@
     }
     
     /// Resolves case value for current case.
+    /// @Deprecated
     ConstantIntTy *getCaseValue() {
       assert(Index < SI->getNumCases() && "Index out the number of cases.");
-      return reinterpret_cast<ConstantIntTy*>(SI->getOperand(2 + Index*2));
+      ConstantRangesSet CRS =
+          reinterpret_cast<Constant*>(SI->getOperand(2 + Index*2));
+      ConstantRangesSet::Range R = CRS.getItem(0);
+      return R.Low;
+    }
+
+    /// Resolves case value for current case.
+    ConstantRangesSet getCaseValueEx() {
+      assert(Index < SI->getNumCases() && "Index out the number of cases.");
+      return reinterpret_cast<Constant*>(SI->getOperand(2 + Index*2));
     }
     
     /// Resolves successor for current case.
@@ -2572,9 +2584,19 @@
     CaseIt(SwitchInst *SI, unsigned CaseNum) : ParentTy(SI, CaseNum) {}
 
     /// Sets the new value for current case.    
+    /// @Deprecated.
     void setValue(ConstantInt *V) {
       assert(Index < SI->getNumCases() && "Index out the number of cases.");
-      SI->setOperand(2 + Index*2, reinterpret_cast<Value*>(V));
+      CRSBuilder CB;
+      CB.add(V);
+      SI->setOperand(2 + Index*2,
+          reinterpret_cast<Value*>((Constant*)CB.getCase()));
+    }
+    
+    /// Sets the new value for current case.
+    void setValueEx(ConstantRangesSet& V) {
+      assert(Index < SI->getNumCases() && "Index out the number of cases.");
+      SI->setOperand(2 + Index*2, reinterpret_cast<Value*>((Constant*)V));      
     }
     
     /// Sets the new successor for current case.
@@ -2654,13 +2676,13 @@
   /// that it is handled by the default handler.
   CaseIt findCaseValue(const ConstantInt *C) {
     for (CaseIt i = case_begin(), e = case_end(); i != e; ++i)
-      if (i.getCaseValue() == C)
+      if (i.getCaseValueEx().isSatisfies(C))
         return i;
     return case_default();
   }
   ConstCaseIt findCaseValue(const ConstantInt *C) const {
     for (ConstCaseIt i = case_begin(), e = case_end(); i != e; ++i)
-      if (i.getCaseValue() == C)
+      if (i.getCaseValueEx().isSatisfies(C))
         return i;
     return case_default();
   }    
@@ -2681,10 +2703,17 @@
   }
 
   /// addCase - Add an entry to the switch instruction...
+  /// @Deprecated
   /// Note:
   /// This action invalidates case_end(). Old case_end() iterator will
   /// point to the added case.
   void addCase(ConstantInt *OnVal, BasicBlock *Dest);
+  
+  /// addCase - Add an entry to the switch instruction.
+  /// Note:
+  /// This action invalidates case_end(). Old case_end() iterator will
+  /// point to the added case.
+  void addCase(ConstantRangesSet& OnVal, BasicBlock *Dest);
 
   /// removeCase - This method removes the specified case and its successor
   /// from the switch instruction. Note that this operation may reorder the
@@ -2703,6 +2732,17 @@
     assert(idx < getNumSuccessors() && "Successor # out of range for switch!");
     setOperand(idx*2+1, (Value*)NewSucc);
   }
+  
+  uint16_t Hash() const {
+    uint32_t NumberOfCases = (uint32_t)getNumCases();
+    uint16_t Hash = (0xFFFF & NumberOfCases) ^ (NumberOfCases >> 16);
+    for (ConstCaseIt i = case_begin(), e = case_end();
+         i != e; ++i) {
+      uint32_t NumItems = (uint32_t)i.getCaseValueEx().getNumItems(); 
+      Hash = (Hash << 1) ^ (0xFFFF & NumItems) ^ (NumItems >> 16);
+    }
+    return Hash;
+  }  
 
   // Methods for support type inquiry through isa, cast, and dyn_cast:
   static inline bool classof(const SwitchInst *) { return true; }

Modified: llvm/trunk/include/llvm/Support/ConstantRangesSet.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/ConstantRangesSet.h?rev=156704&r1=156703&r2=156704&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/ConstantRangesSet.h (original)
+++ llvm/trunk/include/llvm/Support/ConstantRangesSet.h Sat May 12 05:48:17 2012
@@ -48,8 +48,15 @@
   Constant *Array;
 public:
   
+  bool IsWide;
+  
   // implicit
-  ConstantRangesSet(Constant *V) : Array(V) {}
+  ConstantRangesSet(Constant *V) : Array(V) {
+    ArrayType *ArrTy = cast<ArrayType>(Array->getType());
+    VectorType *VecTy = cast<VectorType>(ArrTy->getElementType());
+    IntegerType *IntTy = cast<IntegerType>(VecTy->getElementType());
+    IsWide = IntTy->getBitWidth() > 64;    
+  }
   
   operator Constant*() { return Array; }
   operator const Constant*() const { return Array; }
@@ -230,6 +237,13 @@
     return cast<ArrayType>(Array->getType())->getNumElements();
   }
   
+  bool isWideNumberFormat() const { return IsWide; }
+  
+  bool isSingleNumber(unsigned idx) const {
+    Constant *CV = Array->getAggregateElement(idx);
+    return cast<VectorType>(CV->getType())->getNumElements() == 1;
+  }
+  
   /// Returns set the size, that equals number of all values + sizes of all
   /// ranges.
   /// Ranges set is considered as flat numbers collection.

Modified: llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp?rev=156704&r1=156703&r2=156704&view=diff
==============================================================================
--- llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp (original)
+++ llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp Sat May 12 05:48:17 2012
@@ -28,6 +28,10 @@
 #include "llvm/OperandTraits.h"
 using namespace llvm;
 
+enum {
+  SWITCH_INST_MAGIC = 0x4B5 // May 2012 => 1205 => Hex
+};
+
 void BitcodeReader::materializeForwardReferencedFunctions() {
   while (!BlockAddrFwdRefs.empty()) {
     Function *F = BlockAddrFwdRefs.begin()->first;
@@ -927,6 +931,16 @@
   return false;
 }
 
+APInt ReadWideAPInt(const uint64_t *Vals, unsigned ActiveWords,
+                    unsigned TypeBits) {
+  SmallVector<uint64_t, 8> Words;
+  Words.resize(ActiveWords);
+  for (unsigned i = 0; i != ActiveWords; ++i)
+    Words[i] = DecodeSignRotatedValue(Vals[i]);
+  
+  return APInt(TypeBits, Words);
+}
+
 bool BitcodeReader::ParseConstants() {
   if (Stream.EnterSubBlock(bitc::CONSTANTS_BLOCK_ID))
     return Error("Malformed block record");
@@ -983,13 +997,11 @@
         return Error("Invalid WIDE_INTEGER record");
 
       unsigned NumWords = Record.size();
-      SmallVector<uint64_t, 8> Words;
-      Words.resize(NumWords);
-      for (unsigned i = 0; i != NumWords; ++i)
-        Words[i] = DecodeSignRotatedValue(Record[i]);
-      V = ConstantInt::get(Context,
-                           APInt(cast<IntegerType>(CurTy)->getBitWidth(),
-                                 Words));
+      
+      APInt VInt = ReadWideAPInt(&Record[0], NumWords,
+          cast<IntegerType>(CurTy)->getBitWidth());
+      V = ConstantInt::get(Context, VInt);
+      
       break;
     }
     case bitc::CST_CODE_FLOAT: {    // FLOAT: [fpval]
@@ -2221,6 +2233,62 @@
       break;
     }
     case bitc::FUNC_CODE_INST_SWITCH: { // SWITCH: [opty, op0, op1, ...]
+      // Check magic 
+      if ((Record[0] >> 16) == SWITCH_INST_MAGIC) {
+        // New SwitchInst format with case ranges.
+        
+        Type *OpTy = getTypeByID(Record[1]);
+        unsigned ValueBitWidth = cast<IntegerType>(OpTy)->getBitWidth();
+
+        Value *Cond = getFnValueByID(Record[2], OpTy);
+        BasicBlock *Default = getBasicBlock(Record[3]);
+        if (OpTy == 0 || Cond == 0 || Default == 0)
+          return Error("Invalid SWITCH record");
+
+        unsigned NumCases = Record[4];
+        
+        SwitchInst *SI = SwitchInst::Create(Cond, Default, NumCases);
+        InstructionList.push_back(SI);
+        
+        unsigned CurIdx = 5;
+        for (unsigned i = 0; i != NumCases; ++i) {
+          CRSBuilder CaseBuilder;
+          unsigned NumItems = Record[CurIdx++];
+          for (unsigned ci = 0; ci != NumItems; ++ci) {
+            bool isSingleNumber = Record[CurIdx++];
+            
+            APInt Low;
+            unsigned ActiveWords = 1;
+            if (ValueBitWidth > 64)
+              ActiveWords = Record[CurIdx++];
+            Low = ReadWideAPInt(&Record[CurIdx], ActiveWords, ValueBitWidth);
+            CurIdx += ActiveWords;
+            
+            if (!isSingleNumber) {
+              ActiveWords = 1;
+              if (ValueBitWidth > 64)
+                ActiveWords = Record[CurIdx++];
+              APInt High =
+                  ReadWideAPInt(&Record[CurIdx], ActiveWords, ValueBitWidth);
+              CaseBuilder.add(cast<ConstantInt>(ConstantInt::get(OpTy, Low)),
+                              cast<ConstantInt>(ConstantInt::get(OpTy, High)));
+              CurIdx += ActiveWords;
+            } else
+              CaseBuilder.add(cast<ConstantInt>(ConstantInt::get(OpTy, Low)));
+          }
+          BasicBlock *DestBB = getBasicBlock(Record[CurIdx++]);
+          ConstantRangesSet Case = CaseBuilder.getCase(); 
+          SI->addCase(Case, DestBB);
+        }
+        uint16_t Hash = SI->Hash();
+        if (Hash != (Record[0] & 0xFFFF))
+          return Error("Invalid SWITCH record");
+        I = SI;
+        break;
+      }
+      
+      // Old SwitchInst format without case ranges.
+      
       if (Record.size() < 3 || (Record.size() & 1) == 0)
         return Error("Invalid SWITCH record");
       Type *OpTy = getTypeByID(Record[0]);

Modified: llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp?rev=156704&r1=156703&r2=156704&view=diff
==============================================================================
--- llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp (original)
+++ llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp Sat May 12 05:48:17 2012
@@ -62,7 +62,10 @@
   FUNCTION_INST_CAST_ABBREV,
   FUNCTION_INST_RET_VOID_ABBREV,
   FUNCTION_INST_RET_VAL_ABBREV,
-  FUNCTION_INST_UNREACHABLE_ABBREV
+  FUNCTION_INST_UNREACHABLE_ABBREV,
+  
+  // SwitchInst Magic
+  SWITCH_INST_MAGIC = 0x4B5 // May 2012 => 1205 => Hex
 };
 
 static unsigned GetEncodedCastOpcode(unsigned Opcode) {
@@ -719,6 +722,41 @@
   Stream.ExitBlock();
 }
 
+static void EmitAPInt(SmallVectorImpl<uint64_t> &Vals,
+                      unsigned &Code, unsigned &AbbrevToUse, const APInt &Val,
+                      bool EmitSizeForWideNumbers = false
+                      ) {
+  if (Val.getBitWidth() <= 64) {
+    uint64_t V = Val.getSExtValue();
+    if ((int64_t)V >= 0)
+      Vals.push_back(V << 1);
+    else
+      Vals.push_back((-V << 1) | 1);
+    Code = bitc::CST_CODE_INTEGER;
+    AbbrevToUse = CONSTANTS_INTEGER_ABBREV;
+  } else {
+    // Wide integers, > 64 bits in size.
+    // We have an arbitrary precision integer value to write whose
+    // bit width is > 64. However, in canonical unsigned integer
+    // format it is likely that the high bits are going to be zero.
+    // So, we only write the number of active words.
+    unsigned NWords = Val.getActiveWords();
+    
+    if (EmitSizeForWideNumbers)
+      Vals.push_back(NWords);
+    
+    const uint64_t *RawWords = Val.getRawData();
+    for (unsigned i = 0; i != NWords; ++i) {
+      int64_t V = RawWords[i];
+      if (V >= 0)
+        Vals.push_back(V << 1);
+      else
+        Vals.push_back((-V << 1) | 1);
+    }
+    Code = bitc::CST_CODE_WIDE_INTEGER;
+  }
+}
+
 static void WriteConstants(unsigned FirstVal, unsigned LastVal,
                            const ValueEnumerator &VE,
                            BitstreamWriter &Stream, bool isGlobal) {
@@ -801,30 +839,7 @@
     } else if (isa<UndefValue>(C)) {
       Code = bitc::CST_CODE_UNDEF;
     } else if (const ConstantInt *IV = dyn_cast<ConstantInt>(C)) {
-      if (IV->getBitWidth() <= 64) {
-        uint64_t V = IV->getSExtValue();
-        if ((int64_t)V >= 0)
-          Record.push_back(V << 1);
-        else
-          Record.push_back((-V << 1) | 1);
-        Code = bitc::CST_CODE_INTEGER;
-        AbbrevToUse = CONSTANTS_INTEGER_ABBREV;
-      } else {                             // Wide integers, > 64 bits in size.
-        // We have an arbitrary precision integer value to write whose
-        // bit width is > 64. However, in canonical unsigned integer
-        // format it is likely that the high bits are going to be zero.
-        // So, we only write the number of active words.
-        unsigned NWords = IV->getValue().getActiveWords();
-        const uint64_t *RawWords = IV->getValue().getRawData();
-        for (unsigned i = 0; i != NWords; ++i) {
-          int64_t V = RawWords[i];
-          if (V >= 0)
-            Record.push_back(V << 1);
-          else
-            Record.push_back((-V << 1) | 1);
-        }
-        Code = bitc::CST_CODE_WIDE_INTEGER;
-      }
+      EmitAPInt(Record, Code, AbbrevToUse, IV->getValue());
     } else if (const ConstantFP *CFP = dyn_cast<ConstantFP>(C)) {
       Code = bitc::CST_CODE_FLOAT;
       Type *Ty = CFP->getType();
@@ -1137,16 +1152,45 @@
     break;
   case Instruction::Switch:
     {
+      // Redefine Vals, since here we need to use 64 bit values
+      // explicitly to store large APInt numbers.
+      SmallVector<uint64_t, 128> Vals64;
+      
       Code = bitc::FUNC_CODE_INST_SWITCH;
       SwitchInst &SI = cast<SwitchInst>(I);
-      Vals.push_back(VE.getTypeID(SI.getCondition()->getType()));
-      Vals.push_back(VE.getValueID(SI.getCondition()));
-      Vals.push_back(VE.getValueID(SI.getDefaultDest()));
+      
+      uint32_t SwitchRecordHeader = SI.Hash() | (SWITCH_INST_MAGIC << 16); 
+      Vals64.push_back(SwitchRecordHeader);      
+      
+      Vals64.push_back(VE.getTypeID(SI.getCondition()->getType()));
+      Vals64.push_back(VE.getValueID(SI.getCondition()));
+      Vals64.push_back(VE.getValueID(SI.getDefaultDest()));
+      Vals64.push_back(SI.getNumCases());
       for (SwitchInst::CaseIt i = SI.case_begin(), e = SI.case_end();
            i != e; ++i) {
-        Vals.push_back(VE.getValueID(i.getCaseValue()));
-        Vals.push_back(VE.getValueID(i.getCaseSuccessor()));
+        ConstantRangesSet CRS = i.getCaseValueEx();
+        Vals64.push_back(CRS.getNumItems());
+        for (unsigned ri = 0, rn = CRS.getNumItems(); ri != rn; ++ri) {
+          ConstantRangesSet::Range r = CRS.getItem(ri);
+
+          Vals64.push_back(CRS.isSingleNumber(ri));
+
+          const APInt &Low = r.Low->getValue();
+          const APInt &High = r.High->getValue();
+          unsigned Code, Abbrev; // will unused.
+          
+          EmitAPInt(Vals64, Code, Abbrev, Low, true);
+          if (r.Low != r.High)
+            EmitAPInt(Vals64, Code, Abbrev, High, true);
+        }
+        Vals64.push_back(VE.getValueID(i.getCaseSuccessor()));
       }
+      
+      Stream.EmitRecord(Code, Vals64, AbbrevToUse);
+      
+      // Also do expected action - clear external Vals collection:
+      Vals.clear();
+      return;
     }
     break;
   case Instruction::IndirectBr:

Modified: llvm/trunk/lib/VMCore/Instructions.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/VMCore/Instructions.cpp?rev=156704&r1=156703&r2=156704&view=diff
==============================================================================
--- llvm/trunk/lib/VMCore/Instructions.cpp (original)
+++ llvm/trunk/lib/VMCore/Instructions.cpp Sat May 12 05:48:17 2012
@@ -3169,6 +3169,13 @@
 /// addCase - Add an entry to the switch instruction...
 ///
 void SwitchInst::addCase(ConstantInt *OnVal, BasicBlock *Dest) {
+  CRSBuilder CB;
+  CB.add(OnVal);
+  ConstantRangesSet CRS = CB.getCase();
+  addCase(CRS, Dest);
+}
+
+void SwitchInst::addCase(ConstantRangesSet& OnVal, BasicBlock *Dest) {
   unsigned NewCaseIdx = getNumCases(); 
   unsigned OpNo = NumOperands;
   if (OpNo+2 > ReservedSpace)
@@ -3177,7 +3184,7 @@
   assert(OpNo+1 < ReservedSpace && "Growing didn't work!");
   NumOperands = OpNo+2;
   CaseIt Case(this, NewCaseIdx);
-  Case.setValue(OnVal);
+  Case.setValueEx(OnVal);
   Case.setSuccessor(Dest);
 }
 

Added: llvm/trunk/test/Bitcode/2012-05-07-SwitchInstRangesSupport.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Bitcode/2012-05-07-SwitchInstRangesSupport.ll?rev=156704&view=auto
==============================================================================
--- llvm/trunk/test/Bitcode/2012-05-07-SwitchInstRangesSupport.ll (added)
+++ llvm/trunk/test/Bitcode/2012-05-07-SwitchInstRangesSupport.ll Sat May 12 05:48:17 2012
@@ -0,0 +1,33 @@
+; RUN: rm -f %t.bc
+; RUN: rm -f %t.ll
+; RUN: rm -f %t2.bc
+; RUN: rm -f %t2.ll
+; RUN: llvm-as %s -o %t.bc
+; RUN: llvm-dis %t.bc -o - | tail -n +2 > %t.ll
+; RUN: llvm-as %t.ll -o %t2.bc
+; RUN: llvm-dis %t2.bc -o - | tail -n +2 > %t2.ll
+; RUN: diff %t.ll %t2.ll | not grep .*
+
+define void @test() {
+  %mem = alloca i32
+  store i32 2, i32* %mem
+  %c = load i32* %mem
+  switch i32 %c, label %exit [
+      i32 1, label %exit
+      i32 2, label %exit
+  ]
+exit:
+  ret void
+}
+define void @test_wide() {
+  %mem = alloca i256
+  store i256 2, i256* %mem
+  %c = load i256* %mem
+  switch i256 %c, label %exit [
+      i256 123456789012345678901234567890, label %exit
+      i256 2, label %exit
+  ]
+exit:
+  ret void
+}
+





More information about the llvm-commits mailing list