Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(111)

Unified Diff: lib/Transforms/NaCl/ExpandStructRegs.cpp

Issue 460053003: PNaCl: Handle nested structure types in -expand-struct-regs. (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-llvm.git@master
Patch Set: Forgot a small change. Created 6 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: lib/Transforms/NaCl/ExpandStructRegs.cpp
diff --git a/lib/Transforms/NaCl/ExpandStructRegs.cpp b/lib/Transforms/NaCl/ExpandStructRegs.cpp
index 71f7f286f82232a7b27459909b9ba373b1a42a05..000e08c5672d06c9ec56caaba565b77832b9c4a9 100644
--- a/lib/Transforms/NaCl/ExpandStructRegs.cpp
+++ b/lib/Transforms/NaCl/ExpandStructRegs.cpp
@@ -21,7 +21,6 @@
//
// ExpandStructRegs does not handle:
//
-// * Nested struct types.
// * Array types.
// * Function types containing arguments or return values of struct
// type without the "byval" or "sret" attributes. Since by-value
@@ -63,20 +62,27 @@ char ExpandStructRegs::ID = 0;
INITIALIZE_PASS(ExpandStructRegs, "expand-struct-regs",
"Expand out variables with struct types", false, false)
-static void SplitUpPHINode(PHINode *Phi) {
+static bool DoAnotherPass(Type *Ty) { return isa<StructType>(Ty); }
+static bool DoAnotherPass(Value *V) { return DoAnotherPass(V->getType()); }
+
+static bool SplitUpPHINode(PHINode *Phi) {
StructType *STy = cast<StructType>(Phi->getType());
Value *NewStruct = UndefValue::get(STy);
Instruction *NewStructInsertPt = Phi->getParent()->getFirstInsertionPt();
+ bool NeedsAnotherPass = false;
+
// Create a separate PHINode for each struct field.
for (unsigned Index = 0; Index < STy->getNumElements(); ++Index) {
SmallVector<unsigned, 1> EVIndexes;
EVIndexes.push_back(Index);
- PHINode *NewPhi = PHINode::Create(
- STy->getElementType(Index), Phi->getNumIncomingValues(),
- Phi->getName() + ".index", Phi);
+ Type *ElemTy = STy->getElementType(Index);
+ NeedsAnotherPass = NeedsAnotherPass || DoAnotherPass(ElemTy);
+
+ PHINode *NewPhi = PHINode::Create(ElemTy, Phi->getNumIncomingValues(),
+ Phi->getName() + ".index", Phi);
CopyDebug(NewPhi, Phi);
for (unsigned PhiIndex = 0; PhiIndex < Phi->getNumIncomingValues();
++PhiIndex) {
@@ -96,12 +102,15 @@ static void SplitUpPHINode(PHINode *Phi) {
}
Phi->replaceAllUsesWith(NewStruct);
Phi->eraseFromParent();
+
+ return NeedsAnotherPass;
}
-static void SplitUpSelect(SelectInst *Select) {
+static bool SplitUpSelect(SelectInst *Select) {
StructType *STy = cast<StructType>(Select->getType());
Value *NewStruct = UndefValue::get(STy);
+ bool NeedsAnotherPass = false;
// Create a separate SelectInst for each struct field.
for (unsigned Index = 0; Index < STy->getNumElements(); ++Index) {
SmallVector<unsigned, 1> EVIndexes;
@@ -119,6 +128,8 @@ static void SplitUpSelect(SelectInst *Select) {
SelectInst::Create(Select->getCondition(), TrueVal, FalseVal,
Select->getName() + ".index", Select), Select);
+ NeedsAnotherPass = NeedsAnotherPass || DoAnotherPass(NewSelect);
+
// Reconstruct the original struct value.
NewStruct = CopyDebug(
InsertValueInst::Create(NewStruct, NewSelect, EVIndexes,
@@ -127,6 +138,8 @@ static void SplitUpSelect(SelectInst *Select) {
}
Select->replaceAllUsesWith(NewStruct);
Select->eraseFromParent();
+
+ return NeedsAnotherPass;
}
template <class InstType>
@@ -144,8 +157,10 @@ static void ProcessLoadOrStoreAttrs(InstType *Dest, InstType *Src) {
Dest->setAlignment(1);
}
-static void SplitUpStore(StoreInst *Store) {
+static bool SplitUpStore(StoreInst *Store) {
StructType *STy = cast<StructType>(Store->getValueOperand()->getType());
+
+ bool NeedsAnotherPass = false;
// Create a separate store instruction for each struct field.
for (unsigned Index = 0; Index < STy->getNumElements(); ++Index) {
SmallVector<Value *, 2> Indexes;
@@ -155,6 +170,9 @@ static void SplitUpStore(StoreInst *Store) {
Store->getPointerOperand(), Indexes,
Store->getPointerOperand()->getName() + ".index",
Store), Store);
+ NeedsAnotherPass =
+ NeedsAnotherPass || DoAnotherPass(GEP->getType()->getContainedType(0));
+
SmallVector<unsigned, 1> EVIndexes;
EVIndexes.push_back(Index);
Value *Field = ExtractValueInst::Create(Store->getValueOperand(),
@@ -163,12 +181,15 @@ static void SplitUpStore(StoreInst *Store) {
ProcessLoadOrStoreAttrs(NewStore, Store);
}
Store->eraseFromParent();
+
+ return NeedsAnotherPass;
}
-static void SplitUpLoad(LoadInst *Load) {
+static bool SplitUpLoad(LoadInst *Load) {
StructType *STy = cast<StructType>(Load->getType());
Value *NewStruct = UndefValue::get(STy);
+ bool NeedsAnotherPass = false;
// Create a separate load instruction for each struct field.
for (unsigned Index = 0; Index < STy->getNumElements(); ++Index) {
SmallVector<Value *, 2> Indexes;
@@ -178,6 +199,8 @@ static void SplitUpLoad(LoadInst *Load) {
GetElementPtrInst::Create(Load->getPointerOperand(), Indexes,
Load->getName() + ".index", Load), Load);
LoadInst *NewLoad = new LoadInst(GEP, Load->getName() + ".field", Load);
+
+ NeedsAnotherPass = NeedsAnotherPass || DoAnotherPass(NewLoad);
ProcessLoadOrStoreAttrs(NewLoad, Load);
// Reconstruct the struct value.
@@ -189,44 +212,118 @@ static void SplitUpLoad(LoadInst *Load) {
}
Load->replaceAllUsesWith(NewStruct);
Load->eraseFromParent();
+
+ return NeedsAnotherPass;
}
-static bool ExpandExtractValue(ExtractValueInst *EV) {
+static bool ExpandExtractValue(ExtractValueInst *EV, bool &NeedsAnotherPass) {
// Search for the insertvalue instruction that inserts the struct field
// referenced by this extractvalue instruction, excluding CmpXchg which
// returns a struct and is handled by RewriteAtomics.
Value *StructVal = EV->getAggregateOperand();
- Value *ResultField;
+ Value *ResultField = nullptr;
+ size_t I = 0;
Mark Seaborn 2014/12/09 20:39:46 "I" is too cryptic for an index used across multip
Richard Diamond 2014/12/10 00:58:06 Done.
+
if (isa<AtomicCmpXchgInst>(StructVal))
return false;
+
for (;;) {
if (InsertValueInst *IV = dyn_cast<InsertValueInst>(StructVal)) {
- if (EV->getNumIndices() != 1 || IV->getNumIndices() != 1) {
- errs() << "Value: " << *EV << "\n";
- errs() << "Value: " << *IV << "\n";
- report_fatal_error("ExpandStructRegs does not handle nested structs");
+ size_t J = 0;
+ for (; I < EV->getIndices().size() && J < IV->getIndices().size();
+ ++J, ++I) {
Mark Seaborn 2014/12/09 20:39:46 This doesn't look right. You increment "I", but "
Richard Diamond 2014/12/10 00:58:05 Yes, see line 242 ((EVIndex + 1 == EV->getIndices(
+ const bool Equal = (EV->getIndices()[I] == IV->getIndices()[J]);
+ if (J + 1 == IV->getIndices().size() && Equal) {
+ if (I + 1 == EV->getIndices().size()) {
+ // Match
+ ResultField = IV->getInsertedValueOperand();
+ } else {
+ StructVal = IV->getInsertedValueOperand();
+ ++I;
+ }
+ break;
+ } else if (!Equal) {
+ // No match. Try the next struct value in the chain.
+ StructVal = IV->getAggregateOperand();
+ break;
+ }
}
- if (EV->getIndices()[0] == IV->getIndices()[0]) {
- ResultField = IV->getInsertedValueOperand();
+ if (ResultField) {
+ break;
+ } else if (I == EV->getIndices().size()) {
+ // We've found an insertvalue that inserts at one or more levels deeper
+ // than this extractvalue.
+ NeedsAnotherPass = true;
+ SmallVector<unsigned, 4> Indices(IV->getIndices().begin() + J,
+ IV->getIndices().end());
+
+ InsertValueInst *Insert = InsertValueInst::Create(
+ UndefValue::get(EV->getType()), IV->getInsertedValueOperand(),
+ Indices, "", EV);
+ ResultField = CopyDebug(Insert, EV);
break;
}
Mark Seaborn 2014/12/09 20:39:46 Can we reach after this "}" with StructVal not hav
Richard Diamond 2014/12/10 00:58:05 No, because all such cases would be caught by the
- // No match. Try the next struct value in the chain.
- StructVal = IV->getAggregateOperand();
} else if (Constant *C = dyn_cast<Constant>(StructVal)) {
- ResultField = ConstantExpr::getExtractValue(C, EV->getIndices());
+ SmallVector<unsigned, 4> Indices(EV->getIndices().begin() + I,
+ EV->getIndices().end());
+ ResultField = ConstantExpr::getExtractValue(C, Indices);
+ break;
+ } else if (isa<LoadInst>(StructVal)) {
+ ResultField = StructVal;
break;
} else {
errs() << "Value: " << *StructVal << "\n";
report_fatal_error("Unrecognized struct value");
}
}
+
+ assert(ResultField);
Mark Seaborn 2014/12/09 20:39:46 Are there inputs for which this assertion would fa
Richard Diamond 2014/12/10 00:58:06 There shouldn't be, but that doesn't prevent a dev
EV->replaceAllUsesWith(ResultField);
EV->eraseFromParent();
return true;
}
+static bool ExpandExtractValues(Function &Func) {
+ bool Changed = false;
+ bool NeedsAnotherPass = false;
+
+ // Expand out all the extractvalue instructions. Also collect up
+ // the insertvalue instructions for later deletion so that we do not
+ // need to make extra passes across the whole function.
+ SmallVector<Instruction *, 10> ToErase;
+ for (auto &BB : Func) {
+ for (BasicBlock::iterator Iter = BB.begin(), E = BB.end();
+ Iter != E; ) {
+ Instruction* Inst = Iter++;
Mark Seaborn 2014/12/09 20:39:46 Nit: LLVM style is " *"
Richard Diamond 2014/12/10 00:58:06 Whoops. Done.
+ if (ExtractValueInst *EV = dyn_cast<ExtractValueInst>(Inst)) {
+ Changed |= ExpandExtractValue(EV, NeedsAnotherPass);
+ } else if (isa<InsertValueInst>(Inst)) {
+ ToErase.push_back(Inst);
Mark Seaborn 2014/12/09 20:39:46 ExpandExtractValue() can create InsertValueInsts,
Richard Diamond 2014/12/10 00:58:05 Actually, extra passes in ExpandExtractValues are
+ Changed = true;
+ }
+ }
+ }
+
+ if (!NeedsAnotherPass) {
+ // Delete the insertvalue instructions. These can reference each
+ // other, so we must do dropAllReferences() before doing
+ // eraseFromParent(), otherwise we will try to erase instructions
+ // that are still referenced.
+ for (Instruction *I : ToErase) {
+ I->dropAllReferences();
+ }
+
+ for (Instruction *I : ToErase) {
+ I->eraseFromParent();
+ }
+ }
+
+ return (NeedsAnotherPass && ExpandExtractValues(Func)) || Changed;
+}
+
bool ExpandStructRegs::runOnFunction(Function &Func) {
bool Changed = false;
+ bool NeedsAnotherPass = false;
// Split up aggregate loads, stores and phi nodes into operations on
Mark Seaborn 2014/12/09 20:39:46 I think there's a completeness problem here: This
Richard Diamond 2014/12/10 00:58:05 I was using recursion, however this patchset is ol
// scalar types. This inserts extractvalue and insertvalue
@@ -238,60 +335,33 @@ bool ExpandStructRegs::runOnFunction(Function &Func) {
Instruction *Inst = Iter++;
if (StoreInst *Store = dyn_cast<StoreInst>(Inst)) {
if (Store->getValueOperand()->getType()->isStructTy()) {
- SplitUpStore(Store);
+ NeedsAnotherPass = SplitUpStore(Store) || NeedsAnotherPass;
JF 2014/12/09 19:20:22 I think this is cleaner: NeedsAnotherPass |= foo
Richard Diamond 2014/12/09 19:39:23 Done.
Changed = true;
}
} else if (LoadInst *Load = dyn_cast<LoadInst>(Inst)) {
if (Load->getType()->isStructTy()) {
- SplitUpLoad(Load);
+ NeedsAnotherPass = SplitUpLoad(Load) || NeedsAnotherPass;
Changed = true;
}
} else if (PHINode *Phi = dyn_cast<PHINode>(Inst)) {
if (Phi->getType()->isStructTy()) {
- SplitUpPHINode(Phi);
+ NeedsAnotherPass = SplitUpPHINode(Phi) || NeedsAnotherPass;
Changed = true;
}
} else if (SelectInst *Select = dyn_cast<SelectInst>(Inst)) {
if (Select->getType()->isStructTy()) {
- SplitUpSelect(Select);
+ NeedsAnotherPass = SplitUpSelect(Select) || NeedsAnotherPass;
Changed = true;
}
}
}
}
- // Expand out all the extractvalue instructions. Also collect up
- // the insertvalue instructions for later deletion so that we do not
- // need to make extra passes across the whole function.
- SmallVector<Instruction *, 10> ToErase;
- for (Function::iterator BB = Func.begin(), E = Func.end();
- BB != E; ++BB) {
- for (BasicBlock::iterator Iter = BB->begin(), E = BB->end();
- Iter != E; ) {
- Instruction *Inst = Iter++;
- if (ExtractValueInst *EV = dyn_cast<ExtractValueInst>(Inst)) {
- Changed |= ExpandExtractValue(EV);
- } else if (isa<InsertValueInst>(Inst)) {
- ToErase.push_back(Inst);
- Changed = true;
- }
- }
+ if (!NeedsAnotherPass) {
+ Changed = ExpandExtractValues(Func) || Changed;
}
- // Delete the insertvalue instructions. These can reference each
- // other, so we must do dropAllReferences() before doing
- // eraseFromParent(), otherwise we will try to erase instructions
- // that are still referenced.
- for (SmallVectorImpl<Instruction *>::iterator I = ToErase.begin(),
- E = ToErase.end();
- I != E; ++I) {
- (*I)->dropAllReferences();
- }
- for (SmallVectorImpl<Instruction *>::iterator I = ToErase.begin(),
- E = ToErase.end();
- I != E; ++I) {
- (*I)->eraseFromParent();
- }
- return Changed;
+
+ return (NeedsAnotherPass && runOnFunction(Func)) || Changed;
JF 2014/12/09 19:20:22 I'm not a fan of the tail recursion, could you jus
Richard Diamond 2014/12/09 19:39:23 Done.
}
FunctionPass *llvm::createExpandStructRegsPass() {
« no previous file with comments | « no previous file | test/Transforms/NaCl/expand-struct-regs.ll » ('j') | test/Transforms/NaCl/expand-struct-regs.ll » ('J')

Powered by Google App Engine
This is Rietveld 408576698