aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Seaborn <mseaborn@chromium.org>2013-06-25 14:05:31 -0700
committerMark Seaborn <mseaborn@chromium.org>2013-06-25 14:05:31 -0700
commite93df18eccc8d9cad27853b805a5a22b124b416d (patch)
treed9473ea0e37dd606ba1cb539a25d5e16106d7d64
parentf0392b56ec11466992bac898e12144a32b843077 (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.cpp36
-rw-r--r--test/Transforms/NaCl/expand-struct-regs.ll11
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