aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/llvm/Instructions.h48
-rw-r--r--include/llvm/Support/ConstantRangesSet.h16
-rw-r--r--lib/Bitcode/Reader/BitcodeReader.cpp82
-rw-r--r--lib/Bitcode/Writer/BitcodeWriter.cpp104
-rw-r--r--lib/VMCore/Instructions.cpp9
-rw-r--r--test/Bitcode/2012-05-07-SwitchInstRangesSupport.ll33
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
+}
+