diff options
author | Mark Seaborn <mseaborn@chromium.org> | 2013-06-25 14:05:31 -0700 |
---|---|---|
committer | Mark Seaborn <mseaborn@chromium.org> | 2013-06-25 14:05:31 -0700 |
commit | e93df18eccc8d9cad27853b805a5a22b124b416d (patch) | |
tree | d9473ea0e37dd606ba1cb539a25d5e16106d7d64 | |
parent | f0392b56ec11466992bac898e12144a32b843077 (diff) |
PNaCl: Fix ExpandStructRegs to handle "select" instructions
The code is similar to the case for handling phi nodes.
It turns out that "select" on struct values can occur in practice with
use of C++ method pointers.
BUG=https://code.google.com/p/nativeclient/issues/detail?id=3514
TEST=*.ll tests + PNaCl toolchain trybots
Review URL: https://codereview.chromium.org/17706002
-rw-r--r-- | lib/Transforms/NaCl/ExpandStructRegs.cpp | 36 | ||||
-rw-r--r-- | test/Transforms/NaCl/expand-struct-regs.ll | 11 |
2 files changed, 47 insertions, 0 deletions
diff --git a/lib/Transforms/NaCl/ExpandStructRegs.cpp b/lib/Transforms/NaCl/ExpandStructRegs.cpp index ac83d33e78..5c11a76c8b 100644 --- a/lib/Transforms/NaCl/ExpandStructRegs.cpp +++ b/lib/Transforms/NaCl/ExpandStructRegs.cpp @@ -97,6 +97,37 @@ static void SplitUpPHINode(PHINode *Phi) { Phi->eraseFromParent(); } +static void SplitUpSelect(SelectInst *Select) { + StructType *STy = cast<StructType>(Select->getType()); + Value *NewStruct = UndefValue::get(STy); + + // Create a separate SelectInst for each struct field. + for (unsigned Index = 0; Index < STy->getNumElements(); ++Index) { + SmallVector<unsigned, 1> EVIndexes; + EVIndexes.push_back(Index); + + Value *TrueVal = CopyDebug( + ExtractValueInst::Create(Select->getTrueValue(), EVIndexes, + Select->getName() + ".extract", Select), + Select); + Value *FalseVal = CopyDebug( + ExtractValueInst::Create(Select->getFalseValue(), EVIndexes, + Select->getName() + ".extract", Select), + Select); + Value *NewSelect = CopyDebug( + SelectInst::Create(Select->getCondition(), TrueVal, FalseVal, + Select->getName() + ".index", Select), Select); + + // Reconstruct the original struct value. + NewStruct = CopyDebug( + InsertValueInst::Create(NewStruct, NewSelect, EVIndexes, + Select->getName() + ".insert", Select), + Select); + } + Select->replaceAllUsesWith(NewStruct); + Select->eraseFromParent(); +} + template <class InstType> static void ProcessLoadOrStoreAttrs(InstType *Dest, InstType *Src) { CopyDebug(Dest, Src); @@ -215,6 +246,11 @@ bool ExpandStructRegs::runOnFunction(Function &Func) { SplitUpPHINode(Phi); Changed = true; } + } else if (SelectInst *Select = dyn_cast<SelectInst>(Inst)) { + if (Select->getType()->isStructTy()) { + SplitUpSelect(Select); + Changed = true; + } } } } diff --git a/test/Transforms/NaCl/expand-struct-regs.ll b/test/Transforms/NaCl/expand-struct-regs.ll index 8291ec5069..0cc2c6db85 100644 --- a/test/Transforms/NaCl/expand-struct-regs.ll +++ b/test/Transforms/NaCl/expand-struct-regs.ll @@ -92,6 +92,17 @@ bb: ; CHECK-NEXT: %phi.index{{.*}} = phi i32 [ %val.field{{.*}}, %entry ], [ %val.field{{.*}}, %entry ] +define void @struct_select_inst(i1 %cond, %struct* %ptr1, %struct* %ptr2) { + %val1 = load %struct* %ptr1 + %val2 = load %struct* %ptr2 + %select = select i1 %cond, %struct %val1, %struct %val2 + ret void +} +; CHECK: define void @struct_select_inst +; CHECK: %select.index{{.*}} = select i1 %cond, i8 %val1.field{{.*}}, i8 %val2.field{{.*}} +; CHECK-NEXT: %select.index{{.*}} = select i1 %cond, i32 %val1.field{{.*}}, i32 %val2.field{{.*}} + + define void @insert_and_extract(i8* %out0, i32* %out1) { %temp = insertvalue %struct undef, i8 100, 0 %sval = insertvalue %struct %temp, i32 200, 1 |