aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <alonzakai@gmail.com>2013-12-19 14:33:52 -0800
committerAlon Zakai <alonzakai@gmail.com>2013-12-19 14:33:52 -0800
commit1fd87a8854aa0262ed852713cad9bcd1e8e1fba8 (patch)
tree6d9813e1c5b70975e1de88491effb5ef7669e19e
parentb70920e6fbabec8373fa2d781e6b4573737e9951 (diff)
legalize switch i64
-rw-r--r--lib/Transforms/NaCl/ExpandI64.cpp52
1 files changed, 52 insertions, 0 deletions
diff --git a/lib/Transforms/NaCl/ExpandI64.cpp b/lib/Transforms/NaCl/ExpandI64.cpp
index 8a0c1426a2..d8a6940c1e 100644
--- a/lib/Transforms/NaCl/ExpandI64.cpp
+++ b/lib/Transforms/NaCl/ExpandI64.cpp
@@ -23,6 +23,7 @@
//===------------------------------------------------------------------===//
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringExtras.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
@@ -528,6 +529,46 @@ void ExpandI64::splitInst(Instruction *I, DataLayout& DL) {
Split.ToFix.push_back(D);
break;
}
+ case Instruction::Switch: {
+ // do a switch on the lower 32 bits, into a different basic block for each target, then do a branch in each of those on the high 32 bits
+ SwitchInst* SI = cast<SwitchInst>(I);
+ BasicBlock *DD = SI->getDefaultDest();
+ BasicBlock *SwitchBB = I->getParent();
+ Function *F = SwitchBB->getParent();
+ SplitInfo &Split = Splits[I];
+
+ unsigned NumItems = 0;
+ for (SwitchInst::CaseIt i = SI->case_begin(), e = SI->case_end(); i != e; ++i) {
+ NumItems += i.getCaseValueEx().getNumItems();
+ }
+ SwitchInst *LowSI = SwitchInst::Create(Zero, DD, NumItems, I); // same default destination: if lower bits do not match, go straight to default
+ CopyDebug(LowSI, I);
+ Split.ToFix.push_back(LowSI);
+
+ unsigned Counter = 0;
+ BasicBlock *InsertPoint = SwitchBB;
+
+ for (SwitchInst::CaseIt i = SI->case_begin(), e = SI->case_end(); i != e; ++i) {
+ BasicBlock *BB = i.getCaseSuccessor();
+ const IntegersSubset CaseVal = i.getCaseValueEx();
+ assert(CaseVal.isSingleNumbersOnly());
+ for (unsigned Index = 0; Index < CaseVal.getNumItems(); Index++) {
+ uint64_t Bits = CaseVal.getSingleNumber(Index).toConstantInt()->getZExtValue();
+ uint32_t LowBits = (uint32_t)Bits;
+ uint32_t HighBits = (uint32_t)(Bits >> 32);
+
+ BasicBlock *NewBB = BasicBlock::Create(F->getContext(), "switch64_" + utostr(Counter++), F);
+ NewBB->moveAfter(InsertPoint);
+ InsertPoint = NewBB;
+ Instruction *CheckHigh = CopyDebug(new ICmpInst(*NewBB, ICmpInst::ICMP_EQ, Zero, ConstantInt::get(i32, HighBits)), I);
+ Split.ToFix.push_back(CheckHigh);
+ CopyDebug(BranchInst::Create(BB, DD, CheckHigh, NewBB), I);
+
+ LowSI->addCase(cast<ConstantInt>(ConstantInt::get(i32, LowBits)), NewBB);
+ }
+ }
+ break;
+ }
default: {
dumpIR(I);
assert(0 && "some i64 thing we can't legalize yet");
@@ -691,6 +732,17 @@ void ExpandI64::finalizeInst(Instruction *I) {
}
break;
}
+ case Instruction::Switch: {
+ SwitchInst *SI = dyn_cast<SwitchInst>(I);
+ LowHighPair LH = getLowHigh(SI->getCondition());
+ SwitchInst *NewSI = dyn_cast<SwitchInst>(Split.ToFix[0]);
+ NewSI->setCondition(LH.Low);
+ unsigned Num = Split.ToFix.size();
+ for (unsigned i = 1; i < Num; i++) {
+ Split.ToFix[i]->setOperand(0, LH.High);
+ }
+ break;
+ }
default: dumpIR(I); assert(0);
}
}