@@ -182,12 +182,14 @@ struct llvm::gvn::AvailableValue {
182
182
SimpleVal, // A simple offsetted value that is accessed.
183
183
LoadVal, // A value produced by a load.
184
184
MemIntrin, // A memory intrinsic which is loaded from.
185
- UndefVal // A UndefValue representing a value from dead block (which
185
+ UndefVal, // A UndefValue representing a value from dead block (which
186
186
// is not yet physically removed from the CFG).
187
+ SelectVal, // A pointer select which is loaded from and for which the load
188
+ // can be replace by a value select.
187
189
};
188
190
189
191
// / V - The value that is live out of the block.
190
- PointerIntPair<Value *, 2 , ValType> Val;
192
+ PointerIntPair<Value *, 3 , ValType> Val;
191
193
192
194
// / Offset - The byte offset in Val that is interesting for the load query.
193
195
unsigned Offset = 0 ;
@@ -224,10 +226,19 @@ struct llvm::gvn::AvailableValue {
224
226
return Res;
225
227
}
226
228
229
+ static AvailableValue getSelect (SelectInst *Sel) {
230
+ AvailableValue Res;
231
+ Res.Val .setPointer (Sel);
232
+ Res.Val .setInt (SelectVal);
233
+ Res.Offset = 0 ;
234
+ return Res;
235
+ }
236
+
227
237
bool isSimpleValue () const { return Val.getInt () == SimpleVal; }
228
238
bool isCoercedLoadValue () const { return Val.getInt () == LoadVal; }
229
239
bool isMemIntrinValue () const { return Val.getInt () == MemIntrin; }
230
240
bool isUndefValue () const { return Val.getInt () == UndefVal; }
241
+ bool isSelectValue () const { return Val.getInt () == SelectVal; }
231
242
232
243
Value *getSimpleValue () const {
233
244
assert (isSimpleValue () && " Wrong accessor" );
@@ -244,6 +255,11 @@ struct llvm::gvn::AvailableValue {
244
255
return cast<MemIntrinsic>(Val.getPointer ());
245
256
}
246
257
258
+ SelectInst *getSelectValue () const {
259
+ assert (isSelectValue () && " Wrong accessor" );
260
+ return cast<SelectInst>(Val.getPointer ());
261
+ }
262
+
247
263
// / Emit code at the specified insertion point to adjust the value defined
248
264
// / here to the specified type. This handles various coercion cases.
249
265
Value *MaterializeAdjustedValue (LoadInst *Load, Instruction *InsertPt,
@@ -275,6 +291,10 @@ struct llvm::gvn::AvailableValueInBlock {
275
291
return get (BB, AvailableValue::getUndef ());
276
292
}
277
293
294
+ static AvailableValueInBlock getSelect (BasicBlock *BB, SelectInst *Sel) {
295
+ return get (BB, AvailableValue::getSelect (Sel));
296
+ }
297
+
278
298
// / Emit code at the end of this block to adjust the value defined here to
279
299
// / the specified type. This handles various coercion cases.
280
300
Value *MaterializeAdjustedValue (LoadInst *Load, GVNPass &gvn) const {
@@ -897,6 +917,16 @@ ConstructSSAForLoadSet(LoadInst *Load,
897
917
return SSAUpdate.GetValueInMiddleOfBlock (Load->getParent ());
898
918
}
899
919
920
+ static LoadInst *findDominatingLoad (Value *Ptr, SelectInst *Sel,
921
+ DominatorTree &DT) {
922
+ for (Value *U : Ptr->users ()) {
923
+ auto *LI = dyn_cast<LoadInst>(U);
924
+ if (LI && LI->getParent () == Sel->getParent () && DT.dominates (LI, Sel))
925
+ return LI;
926
+ }
927
+ return nullptr ;
928
+ }
929
+
900
930
Value *AvailableValue::MaterializeAdjustedValue (LoadInst *Load,
901
931
Instruction *InsertPt,
902
932
GVNPass &gvn) const {
@@ -937,6 +967,17 @@ Value *AvailableValue::MaterializeAdjustedValue(LoadInst *Load,
937
967
<< " " << *getMemIntrinValue () << ' \n '
938
968
<< *Res << ' \n '
939
969
<< " \n\n\n " );
970
+ } else if (isSelectValue ()) {
971
+ // Introduce a new value select for a load from an eligible pointer select.
972
+ SelectInst *Sel = getSelectValue ();
973
+ LoadInst *L1 =
974
+ findDominatingLoad (Sel->getOperand (1 ), Sel, gvn.getDominatorTree ());
975
+ LoadInst *L2 =
976
+ findDominatingLoad (Sel->getOperand (2 ), Sel, gvn.getDominatorTree ());
977
+ assert (L1 && L2 &&
978
+ " must be able to obtain dominating loads for both value operands of "
979
+ " the select" );
980
+ Res = SelectInst::Create (Sel->getCondition (), L1, L2, " " , Sel);
940
981
} else {
941
982
llvm_unreachable (" Should not materialize value from dead block" );
942
983
}
@@ -1023,8 +1064,53 @@ static void reportMayClobberedLoad(LoadInst *Load, MemDepResult DepInfo,
1023
1064
ORE->emit (R);
1024
1065
}
1025
1066
1067
+ // / Check if a load from pointer-select \p Address in \p DepBB can be converted
1068
+ // / to a value select. The following conditions need to be satisfied:
1069
+ // / 1. The pointer select (\p Address) must be defined in \p DepBB.
1070
+ // / 2. Both value operands of the pointer select must be loaded in the same
1071
+ // / basic block, before the pointer select.
1072
+ // / 3. There must be no instructions between the found loads and \p End that may
1073
+ // / clobber the loads.
1074
+ static Optional<AvailableValue>
1075
+ tryToConvertLoadOfPtrSelect (BasicBlock *DepBB, BasicBlock::iterator End,
1076
+ Value *Address, DominatorTree &DT, AAResults *AA) {
1077
+
1078
+ auto *Sel = dyn_cast_or_null<SelectInst>(Address);
1079
+ if (!Sel || DepBB != Sel->getParent ())
1080
+ return None;
1081
+
1082
+ LoadInst *L1 = findDominatingLoad (Sel->getOperand (1 ), Sel, DT);
1083
+ LoadInst *L2 = findDominatingLoad (Sel->getOperand (2 ), Sel, DT);
1084
+ if (!L1 || !L2)
1085
+ return None;
1086
+
1087
+ // Ensure there are no accesses that may modify the locations referenced by
1088
+ // either L1 or L2 between L1, L2 and the specified End iterator.
1089
+ Instruction *EarlierLoad = L1->comesBefore (L2) ? L1 : L2;
1090
+ MemoryLocation L1Loc = MemoryLocation::get (L1);
1091
+ MemoryLocation L2Loc = MemoryLocation::get (L2);
1092
+ if (any_of (make_range (EarlierLoad->getIterator (), End), [&](Instruction &I) {
1093
+ return isModSet (AA->getModRefInfo (&I, L1Loc)) ||
1094
+ isModSet (AA->getModRefInfo (&I, L2Loc));
1095
+ }))
1096
+ return None;
1097
+
1098
+ return AvailableValue::getSelect (Sel);
1099
+ }
1100
+
1026
1101
bool GVNPass::AnalyzeLoadAvailability (LoadInst *Load, MemDepResult DepInfo,
1027
1102
Value *Address, AvailableValue &Res) {
1103
+ if (!DepInfo.isDef () && !DepInfo.isClobber ()) {
1104
+ assert (isa<SelectInst>(Address));
1105
+ if (auto R = tryToConvertLoadOfPtrSelect (
1106
+ Load->getParent (), Load->getIterator (), Address, getDominatorTree (),
1107
+ getAliasAnalysis ())) {
1108
+ Res = *R;
1109
+ return true ;
1110
+ }
1111
+ return false ;
1112
+ }
1113
+
1028
1114
assert ((DepInfo.isDef () || DepInfo.isClobber ()) &&
1029
1115
" expected a local dependence" );
1030
1116
assert (Load->isUnordered () && " rules below are incorrect for ordered access" );
@@ -1092,6 +1178,7 @@ bool GVNPass::AnalyzeLoadAvailability(LoadInst *Load, MemDepResult DepInfo,
1092
1178
}
1093
1179
}
1094
1180
}
1181
+
1095
1182
// Nothing known about this clobber, have to be conservative
1096
1183
LLVM_DEBUG (
1097
1184
// fast print dep, using operator<< on instruction is too slow.
@@ -1176,16 +1263,23 @@ void GVNPass::AnalyzeLoadAvailability(LoadInst *Load, LoadDepVect &Deps,
1176
1263
continue ;
1177
1264
}
1178
1265
1179
- if (!DepInfo.isDef () && !DepInfo.isClobber ()) {
1180
- UnavailableBlocks.push_back (DepBB);
1181
- continue ;
1182
- }
1183
-
1184
1266
// The address being loaded in this non-local block may not be the same as
1185
1267
// the pointer operand of the load if PHI translation occurs. Make sure
1186
1268
// to consider the right address.
1187
1269
Value *Address = Deps[i].getAddress ();
1188
1270
1271
+ if (!DepInfo.isDef () && !DepInfo.isClobber ()) {
1272
+ if (auto R = tryToConvertLoadOfPtrSelect (DepBB, DepBB->end (), Address,
1273
+ getDominatorTree (),
1274
+ getAliasAnalysis ())) {
1275
+ ValuesPerBlock.push_back (
1276
+ AvailableValueInBlock::get (DepBB, std::move (*R)));
1277
+ continue ;
1278
+ }
1279
+ UnavailableBlocks.push_back (DepBB);
1280
+ continue ;
1281
+ }
1282
+
1189
1283
AvailableValue AV;
1190
1284
if (AnalyzeLoadAvailability (Load, DepInfo, Address, AV)) {
1191
1285
// subtlety: because we know this was a non-local dependency, we know
@@ -1923,8 +2017,9 @@ bool GVNPass::processLoad(LoadInst *L) {
1923
2017
if (Dep.isNonLocal ())
1924
2018
return processNonLocalLoad (L);
1925
2019
2020
+ Value *Address = L->getPointerOperand ();
1926
2021
// Only handle the local case below
1927
- if (!Dep.isDef () && !Dep.isClobber ()) {
2022
+ if (!Dep.isDef () && !Dep.isClobber () && !isa<SelectInst>(Address) ) {
1928
2023
// This might be a NonFuncLocal or an Unknown
1929
2024
LLVM_DEBUG (
1930
2025
// fast print dep, using operator<< on instruction is too slow.
@@ -1934,7 +2029,7 @@ bool GVNPass::processLoad(LoadInst *L) {
1934
2029
}
1935
2030
1936
2031
AvailableValue AV;
1937
- if (AnalyzeLoadAvailability (L, Dep, L-> getPointerOperand () , AV)) {
2032
+ if (AnalyzeLoadAvailability (L, Dep, Address , AV)) {
1938
2033
Value *AvailableValue = AV.MaterializeAdjustedValue (L, L, *this );
1939
2034
1940
2035
// Replace the load!
0 commit comments