diff options
-rw-r--r-- | include/llvm/Instructions.h | 48 | ||||
-rw-r--r-- | include/llvm/Support/ConstantRangesSet.h | 16 | ||||
-rw-r--r-- | lib/Bitcode/Reader/BitcodeReader.cpp | 82 | ||||
-rw-r--r-- | lib/Bitcode/Writer/BitcodeWriter.cpp | 104 | ||||
-rw-r--r-- | lib/VMCore/Instructions.cpp | 9 | ||||
-rw-r--r-- | test/Bitcode/2012-05-07-SwitchInstRangesSupport.ll | 33 |
6 files changed, 249 insertions, 43 deletions
diff --git a/include/llvm/Instructions.h b/include/llvm/Instructions.h index f6eaf04fd0..d934128e7d 100644 --- a/include/llvm/Instructions.h +++ b/include/llvm/Instructions.h @@ -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 @@ public: } /// 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 @@ public: 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 @@ public: /// 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 @@ public: } /// 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 @@ public: 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; } diff --git a/include/llvm/Support/ConstantRangesSet.h b/include/llvm/Support/ConstantRangesSet.h index 2d3ee8bafa..a3f082f822 100644 --- a/include/llvm/Support/ConstantRangesSet.h +++ b/include/llvm/Support/ConstantRangesSet.h @@ -48,8 +48,15 @@ class ConstantRangesSet { 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 @@ public: 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. diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp index 040f3438fe..49b6e4f42a 100644 --- a/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/lib/Bitcode/Reader/BitcodeReader.cpp @@ -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 @@ bool BitcodeReader::ResolveGlobalAndAliasInits() { 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 @@ bool BitcodeReader::ParseConstants() { 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 @@ bool BitcodeReader::ParseFunctionBody(Function *F) { 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]); diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp index b25d2e96d5..ae250ebe16 100644 --- a/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -62,7 +62,10 @@ enum { 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 @@ static void WriteModuleMetadataStore(const Module *M, BitstreamWriter &Stream) { 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 @@ static void WriteConstants(unsigned FirstVal, unsigned LastVal, } 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 @@ static void WriteInstruction(const Instruction &I, unsigned InstID, 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: diff --git a/lib/VMCore/Instructions.cpp b/lib/VMCore/Instructions.cpp index 6c5db32876..819a090cc3 100644 --- a/lib/VMCore/Instructions.cpp +++ b/lib/VMCore/Instructions.cpp @@ -3169,6 +3169,13 @@ SwitchInst::~SwitchInst() { /// 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 @@ void SwitchInst::addCase(ConstantInt *OnVal, BasicBlock *Dest) { assert(OpNo+1 < ReservedSpace && "Growing didn't work!"); NumOperands = OpNo+2; CaseIt Case(this, NewCaseIdx); - Case.setValue(OnVal); + Case.setValueEx(OnVal); Case.setSuccessor(Dest); } diff --git a/test/Bitcode/2012-05-07-SwitchInstRangesSupport.ll b/test/Bitcode/2012-05-07-SwitchInstRangesSupport.ll new file mode 100644 index 0000000000..4f51ba83b9 --- /dev/null +++ b/test/Bitcode/2012-05-07-SwitchInstRangesSupport.ll @@ -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 +} + |