@@ -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 {
@@ -893,6 +913,16 @@ ConstructSSAForLoadSet(LoadInst *Load,
893
913
return SSAUpdate.GetValueInMiddleOfBlock (Load->getParent ());
894
914
}
895
915
916
+ static LoadInst *findDominatingLoad (Value *Ptr, SelectInst *Sel,
917
+ DominatorTree &DT) {
918
+ for (Value *U : Ptr->users ()) {
919
+ auto *LI = dyn_cast<LoadInst>(U);
920
+ if (LI && LI->getParent () == Sel->getParent () && DT.dominates (LI, Sel))
921
+ return LI;
922
+ }
923
+ return nullptr ;
924
+ }
925
+
896
926
Value *AvailableValue::MaterializeAdjustedValue (LoadInst *Load,
897
927
Instruction *InsertPt,
898
928
GVN &gvn) const {
@@ -933,6 +963,17 @@ Value *AvailableValue::MaterializeAdjustedValue(LoadInst *Load,
933
963
<< " " << *getMemIntrinValue () << ' \n '
934
964
<< *Res << ' \n '
935
965
<< " \n\n\n " );
966
+ } else if (isSelectValue ()) {
967
+ // Introduce a new value select for a load from an eligible pointer select.
968
+ SelectInst *Sel = getSelectValue ();
969
+ LoadInst *L1 =
970
+ findDominatingLoad (Sel->getOperand (1 ), Sel, gvn.getDominatorTree ());
971
+ LoadInst *L2 =
972
+ findDominatingLoad (Sel->getOperand (2 ), Sel, gvn.getDominatorTree ());
973
+ assert (L1 && L2 &&
974
+ " must be able to obtain dominating loads for both value operands of "
975
+ " the select" );
976
+ Res = SelectInst::Create (Sel->getCondition (), L1, L2, " " , Sel);
936
977
} else {
937
978
llvm_unreachable (" Should not materialize value from dead block" );
938
979
}
@@ -1019,8 +1060,53 @@ static void reportMayClobberedLoad(LoadInst *Load, MemDepResult DepInfo,
1019
1060
ORE->emit (R);
1020
1061
}
1021
1062
1063
+ // / Check if a load from pointer-select \p Address in \p DepBB can be converted
1064
+ // / to a value select. The following conditions need to be satisfied:
1065
+ // / 1. The pointer select (\p Address) must be defined in \p DepBB.
1066
+ // / 2. Both value operands of the pointer select must be loaded in the same
1067
+ // / basic block, before the pointer select.
1068
+ // / 3. There must be no instructions between the found loads and \p End that may
1069
+ // / clobber the loads.
1070
+ static Optional<AvailableValue>
1071
+ tryToConvertLoadOfPtrSelect (BasicBlock *DepBB, BasicBlock::iterator End,
1072
+ Value *Address, DominatorTree &DT, AAResults *AA) {
1073
+
1074
+ auto *Sel = dyn_cast_or_null<SelectInst>(Address);
1075
+ if (!Sel || DepBB != Sel->getParent ())
1076
+ return None;
1077
+
1078
+ LoadInst *L1 = findDominatingLoad (Sel->getOperand (1 ), Sel, DT);
1079
+ LoadInst *L2 = findDominatingLoad (Sel->getOperand (2 ), Sel, DT);
1080
+ if (!L1 || !L2)
1081
+ return None;
1082
+
1083
+ // Ensure there are no accesses that may modify the locations referenced by
1084
+ // either L1 or L2 between L1, L2 and the specified End iterator.
1085
+ Instruction *EarlierLoad = L1->comesBefore (L2) ? L1 : L2;
1086
+ MemoryLocation L1Loc = MemoryLocation::get (L1);
1087
+ MemoryLocation L2Loc = MemoryLocation::get (L2);
1088
+ if (any_of (make_range (EarlierLoad->getIterator (), End), [&](Instruction &I) {
1089
+ return isModSet (AA->getModRefInfo (&I, L1Loc)) ||
1090
+ isModSet (AA->getModRefInfo (&I, L2Loc));
1091
+ }))
1092
+ return None;
1093
+
1094
+ return AvailableValue::getSelect (Sel);
1095
+ }
1096
+
1022
1097
bool GVN::AnalyzeLoadAvailability (LoadInst *Load, MemDepResult DepInfo,
1023
1098
Value *Address, AvailableValue &Res) {
1099
+ if (!DepInfo.isDef () && !DepInfo.isClobber ()) {
1100
+ assert (isa<SelectInst>(Address));
1101
+ if (auto R = tryToConvertLoadOfPtrSelect (
1102
+ Load->getParent (), Load->getIterator (), Address, getDominatorTree (),
1103
+ getAliasAnalysis ())) {
1104
+ Res = *R;
1105
+ return true ;
1106
+ }
1107
+ return false ;
1108
+ }
1109
+
1024
1110
assert ((DepInfo.isDef () || DepInfo.isClobber ()) &&
1025
1111
" expected a local dependence" );
1026
1112
assert (Load->isUnordered () && " rules below are incorrect for ordered access" );
@@ -1088,6 +1174,7 @@ bool GVN::AnalyzeLoadAvailability(LoadInst *Load, MemDepResult DepInfo,
1088
1174
}
1089
1175
}
1090
1176
}
1177
+
1091
1178
// Nothing known about this clobber, have to be conservative
1092
1179
LLVM_DEBUG (
1093
1180
// fast print dep, using operator<< on instruction is too slow.
@@ -1173,16 +1260,23 @@ void GVN::AnalyzeLoadAvailability(LoadInst *Load, LoadDepVect &Deps,
1173
1260
continue ;
1174
1261
}
1175
1262
1176
- if (!DepInfo.isDef () && !DepInfo.isClobber ()) {
1177
- UnavailableBlocks.push_back (DepBB);
1178
- continue ;
1179
- }
1180
-
1181
1263
// The address being loaded in this non-local block may not be the same as
1182
1264
// the pointer operand of the load if PHI translation occurs. Make sure
1183
1265
// to consider the right address.
1184
1266
Value *Address = Deps[i].getAddress ();
1185
1267
1268
+ if (!DepInfo.isDef () && !DepInfo.isClobber ()) {
1269
+ if (auto R = tryToConvertLoadOfPtrSelect (DepBB, DepBB->end (), Address,
1270
+ getDominatorTree (),
1271
+ getAliasAnalysis ())) {
1272
+ ValuesPerBlock.push_back (
1273
+ AvailableValueInBlock::get (DepBB, std::move (*R)));
1274
+ continue ;
1275
+ }
1276
+ UnavailableBlocks.push_back (DepBB);
1277
+ continue ;
1278
+ }
1279
+
1186
1280
AvailableValue AV;
1187
1281
if (AnalyzeLoadAvailability (Load, DepInfo, Address, AV)) {
1188
1282
// subtlety: because we know this was a non-local dependency, we know
@@ -1921,8 +2015,9 @@ bool GVN::processLoad(LoadInst *L) {
1921
2015
if (Dep.isNonLocal ())
1922
2016
return processNonLocalLoad (L);
1923
2017
2018
+ Value *Address = L->getPointerOperand ();
1924
2019
// Only handle the local case below
1925
- if (!Dep.isDef () && !Dep.isClobber ()) {
2020
+ if (!Dep.isDef () && !Dep.isClobber () && !isa<SelectInst>(Address) ) {
1926
2021
// This might be a NonFuncLocal or an Unknown
1927
2022
LLVM_DEBUG (
1928
2023
// fast print dep, using operator<< on instruction is too slow.
@@ -1932,7 +2027,7 @@ bool GVN::processLoad(LoadInst *L) {
1932
2027
}
1933
2028
1934
2029
AvailableValue AV;
1935
- if (AnalyzeLoadAvailability (L, Dep, L-> getPointerOperand () , AV)) {
2030
+ if (AnalyzeLoadAvailability (L, Dep, Address , AV)) {
1936
2031
Value *AvailableValue = AV.MaterializeAdjustedValue (L, L, *this );
1937
2032
1938
2033
// Replace the load!
0 commit comments