@@ -181,12 +181,14 @@ struct llvm::gvn::AvailableValue {
181
181
SimpleVal, // A simple offsetted value that is accessed.
182
182
LoadVal, // A value produced by a load.
183
183
MemIntrin, // A memory intrinsic which is loaded from.
184
- UndefVal // A UndefValue representing a value from dead block (which
184
+ UndefVal, // A UndefValue representing a value from dead block (which
185
185
// is not yet physically removed from the CFG).
186
+ SelectVal, // A pointer select which is loaded from and for which the load
187
+ // can be replace by a value select.
186
188
};
187
189
188
190
// / V - The value that is live out of the block.
189
- PointerIntPair<Value *, 2 , ValType> Val;
191
+ PointerIntPair<Value *, 3 , ValType> Val;
190
192
191
193
// / Offset - The byte offset in Val that is interesting for the load query.
192
194
unsigned Offset = 0 ;
@@ -223,10 +225,19 @@ struct llvm::gvn::AvailableValue {
223
225
return Res;
224
226
}
225
227
228
+ static AvailableValue getSelect (SelectInst *Sel) {
229
+ AvailableValue Res;
230
+ Res.Val .setPointer (Sel);
231
+ Res.Val .setInt (SelectVal);
232
+ Res.Offset = 0 ;
233
+ return Res;
234
+ }
235
+
226
236
bool isSimpleValue () const { return Val.getInt () == SimpleVal; }
227
237
bool isCoercedLoadValue () const { return Val.getInt () == LoadVal; }
228
238
bool isMemIntrinValue () const { return Val.getInt () == MemIntrin; }
229
239
bool isUndefValue () const { return Val.getInt () == UndefVal; }
240
+ bool isSelectValue () const { return Val.getInt () == SelectVal; }
230
241
231
242
Value *getSimpleValue () const {
232
243
assert (isSimpleValue () && " Wrong accessor" );
@@ -243,6 +254,11 @@ struct llvm::gvn::AvailableValue {
243
254
return cast<MemIntrinsic>(Val.getPointer ());
244
255
}
245
256
257
+ SelectInst *getSelectValue () const {
258
+ assert (isSelectValue () && " Wrong accessor" );
259
+ return cast<SelectInst>(Val.getPointer ());
260
+ }
261
+
246
262
// / Emit code at the specified insertion point to adjust the value defined
247
263
// / here to the specified type. This handles various coercion cases.
248
264
Value *MaterializeAdjustedValue (LoadInst *Load, Instruction *InsertPt,
@@ -274,6 +290,10 @@ struct llvm::gvn::AvailableValueInBlock {
274
290
return get (BB, AvailableValue::getUndef ());
275
291
}
276
292
293
+ static AvailableValueInBlock getSelect (BasicBlock *BB, SelectInst *Sel) {
294
+ return get (BB, AvailableValue::getSelect (Sel));
295
+ }
296
+
277
297
// / Emit code at the end of this block to adjust the value defined here to
278
298
// / the specified type. This handles various coercion cases.
279
299
Value *MaterializeAdjustedValue (LoadInst *Load, GVN &gvn) const {
@@ -876,6 +896,16 @@ ConstructSSAForLoadSet(LoadInst *Load,
876
896
return SSAUpdate.GetValueInMiddleOfBlock (Load->getParent ());
877
897
}
878
898
899
+ static LoadInst *findDominatingLoad (Value *Ptr, SelectInst *Sel,
900
+ DominatorTree &DT) {
901
+ for (Value *U : Ptr->users ()) {
902
+ auto *LI = dyn_cast<LoadInst>(U);
903
+ if (LI && LI->getParent () == Sel->getParent () && DT.dominates (LI, Sel))
904
+ return LI;
905
+ }
906
+ return nullptr ;
907
+ }
908
+
879
909
Value *AvailableValue::MaterializeAdjustedValue (LoadInst *Load,
880
910
Instruction *InsertPt,
881
911
GVN &gvn) const {
@@ -916,6 +946,17 @@ Value *AvailableValue::MaterializeAdjustedValue(LoadInst *Load,
916
946
<< " " << *getMemIntrinValue () << ' \n '
917
947
<< *Res << ' \n '
918
948
<< " \n\n\n " );
949
+ } else if (isSelectValue ()) {
950
+ // Introduce a new value select for a load from an eligible pointer select.
951
+ SelectInst *Sel = getSelectValue ();
952
+ LoadInst *L1 =
953
+ findDominatingLoad (Sel->getOperand (1 ), Sel, gvn.getDominatorTree ());
954
+ LoadInst *L2 =
955
+ findDominatingLoad (Sel->getOperand (2 ), Sel, gvn.getDominatorTree ());
956
+ assert (L1 && L2 &&
957
+ " must be able to obtain dominating loads for both value operands of "
958
+ " the select" );
959
+ Res = SelectInst::Create (Sel->getCondition (), L1, L2, " " , Sel);
919
960
} else {
920
961
llvm_unreachable (" Should not materialize value from dead block" );
921
962
}
@@ -1002,8 +1043,53 @@ static void reportMayClobberedLoad(LoadInst *Load, MemDepResult DepInfo,
1002
1043
ORE->emit (R);
1003
1044
}
1004
1045
1046
+ // / Check if a load from pointer-select \p Address in \p DepBB can be converted
1047
+ // / to a value select. The following conditions need to be satisfied:
1048
+ // / 1. The pointer select (\p Address) must be defined in \p DepBB.
1049
+ // / 2. Both value operands of the pointer select must be loaded in the same
1050
+ // / basic block, before the pointer select.
1051
+ // / 3. There must be no instructions between the found loads and \p End that may
1052
+ // / clobber the loads.
1053
+ static Optional<AvailableValue>
1054
+ tryToConvertLoadOfPtrSelect (BasicBlock *DepBB, BasicBlock::iterator End,
1055
+ Value *Address, DominatorTree &DT, AAResults *AA) {
1056
+
1057
+ auto *Sel = dyn_cast_or_null<SelectInst>(Address);
1058
+ if (!Sel || DepBB != Sel->getParent ())
1059
+ return None;
1060
+
1061
+ LoadInst *L1 = findDominatingLoad (Sel->getOperand (1 ), Sel, DT);
1062
+ LoadInst *L2 = findDominatingLoad (Sel->getOperand (2 ), Sel, DT);
1063
+ if (!L1 || !L2)
1064
+ return None;
1065
+
1066
+ // Ensure there are no accesses that may modify the locations referenced by
1067
+ // either L1 or L2 between L1, L2 and the specified End iterator.
1068
+ Instruction *EarlierLoad = L1->comesBefore (L2) ? L1 : L2;
1069
+ MemoryLocation L1Loc = MemoryLocation::get (L1);
1070
+ MemoryLocation L2Loc = MemoryLocation::get (L2);
1071
+ if (any_of (make_range (EarlierLoad->getIterator (), End), [&](Instruction &I) {
1072
+ return isModSet (AA->getModRefInfo (&I, L1Loc)) ||
1073
+ isModSet (AA->getModRefInfo (&I, L2Loc));
1074
+ }))
1075
+ return None;
1076
+
1077
+ return AvailableValue::getSelect (Sel);
1078
+ }
1079
+
1005
1080
bool GVN::AnalyzeLoadAvailability (LoadInst *Load, MemDepResult DepInfo,
1006
1081
Value *Address, AvailableValue &Res) {
1082
+ if (!DepInfo.isDef () && !DepInfo.isClobber ()) {
1083
+ assert (isa<SelectInst>(Address));
1084
+ if (auto R = tryToConvertLoadOfPtrSelect (
1085
+ Load->getParent (), Load->getIterator (), Address, getDominatorTree (),
1086
+ getAliasAnalysis ())) {
1087
+ Res = *R;
1088
+ return true ;
1089
+ }
1090
+ return false ;
1091
+ }
1092
+
1007
1093
assert ((DepInfo.isDef () || DepInfo.isClobber ()) &&
1008
1094
" expected a local dependence" );
1009
1095
assert (Load->isUnordered () && " rules below are incorrect for ordered access" );
@@ -1071,6 +1157,7 @@ bool GVN::AnalyzeLoadAvailability(LoadInst *Load, MemDepResult DepInfo,
1071
1157
}
1072
1158
}
1073
1159
}
1160
+
1074
1161
// Nothing known about this clobber, have to be conservative
1075
1162
LLVM_DEBUG (
1076
1163
// fast print dep, using operator<< on instruction is too slow.
@@ -1156,16 +1243,23 @@ void GVN::AnalyzeLoadAvailability(LoadInst *Load, LoadDepVect &Deps,
1156
1243
continue ;
1157
1244
}
1158
1245
1159
- if (!DepInfo.isDef () && !DepInfo.isClobber ()) {
1160
- UnavailableBlocks.push_back (DepBB);
1161
- continue ;
1162
- }
1163
-
1164
1246
// The address being loaded in this non-local block may not be the same as
1165
1247
// the pointer operand of the load if PHI translation occurs. Make sure
1166
1248
// to consider the right address.
1167
1249
Value *Address = Deps[i].getAddress ();
1168
1250
1251
+ if (!DepInfo.isDef () && !DepInfo.isClobber ()) {
1252
+ if (auto R = tryToConvertLoadOfPtrSelect (DepBB, DepBB->end (), Address,
1253
+ getDominatorTree (),
1254
+ getAliasAnalysis ())) {
1255
+ ValuesPerBlock.push_back (
1256
+ AvailableValueInBlock::get (DepBB, std::move (*R)));
1257
+ continue ;
1258
+ }
1259
+ UnavailableBlocks.push_back (DepBB);
1260
+ continue ;
1261
+ }
1262
+
1169
1263
AvailableValue AV;
1170
1264
if (AnalyzeLoadAvailability (Load, DepInfo, Address, AV)) {
1171
1265
// subtlety: because we know this was a non-local dependency, we know
@@ -1902,8 +1996,9 @@ bool GVN::processLoad(LoadInst *L) {
1902
1996
if (Dep.isNonLocal ())
1903
1997
return processNonLocalLoad (L);
1904
1998
1999
+ Value *Address = L->getPointerOperand ();
1905
2000
// Only handle the local case below
1906
- if (!Dep.isDef () && !Dep.isClobber ()) {
2001
+ if (!Dep.isDef () && !Dep.isClobber () && !isa<SelectInst>(Address) ) {
1907
2002
// This might be a NonFuncLocal or an Unknown
1908
2003
LLVM_DEBUG (
1909
2004
// fast print dep, using operator<< on instruction is too slow.
@@ -1913,7 +2008,7 @@ bool GVN::processLoad(LoadInst *L) {
1913
2008
}
1914
2009
1915
2010
AvailableValue AV;
1916
- if (AnalyzeLoadAvailability (L, Dep, L-> getPointerOperand () , AV)) {
2011
+ if (AnalyzeLoadAvailability (L, Dep, Address , AV)) {
1917
2012
Value *AvailableValue = AV.MaterializeAdjustedValue (L, L, *this );
1918
2013
1919
2014
// Replace the load!
0 commit comments