44
44
#include " llvm/IR/IntrinsicInst.h"
45
45
#include " llvm/IR/Intrinsics.h"
46
46
#include " llvm/IR/Operator.h"
47
+ #include " llvm/IR/PatternMatch.h"
47
48
#include " llvm/IR/Type.h"
48
49
#include " llvm/IR/User.h"
49
50
#include " llvm/IR/Value.h"
63
64
#define DEBUG_TYPE " basicaa"
64
65
65
66
using namespace llvm ;
67
+ using namespace llvm ::PatternMatch;
66
68
67
69
// / Enable analysis of recursive PHI nodes.
68
70
static cl::opt<bool > EnableRecPhiAnalysis (" basic-aa-recphi" , cl::Hidden,
@@ -344,13 +346,20 @@ struct LinearExpression {
344
346
345
347
// / Analyzes the specified value as a linear expression: "A*V + B", where A and
346
348
// / B are constant integers.
347
- static LinearExpression GetLinearExpression (
348
- const CastedValue &Val, const DataLayout &DL, unsigned Depth,
349
- AssumptionCache *AC, DominatorTree *DT) {
349
+ static LinearExpression GetLinearExpression (const CastedValue &Val,
350
+ const DataLayout &DL,
351
+ unsigned Depth, AssumptionCache *AC,
352
+ DominatorTree *DT) {
350
353
// Limit our recursion depth.
351
354
if (Depth == 6 )
352
355
return Val;
353
356
357
+ // If llvm.vscale is matched, set linear expression with scale 1 and offset 0
358
+ if (match (Val.V , m_VScale ())) {
359
+ return LinearExpression (Val, APInt (Val.getBitWidth (), 1 ),
360
+ APInt (Val.getBitWidth (), 0 ), true );
361
+ }
362
+
354
363
if (const ConstantInt *Const = dyn_cast<ConstantInt>(Val.V ))
355
364
return LinearExpression (Val, APInt (Val.getBitWidth (), 0 ),
356
365
Val.evaluateWith (Const->getValue ()), true );
@@ -457,6 +466,9 @@ struct VariableGEPIndex {
457
466
CastedValue Val;
458
467
APInt Scale;
459
468
469
+ // A value representing vscale quantity in a GEP expression
470
+ bool IsVScale;
471
+
460
472
// Context instruction to use when querying information about this index.
461
473
const Instruction *CxtI;
462
474
@@ -479,13 +491,10 @@ struct VariableGEPIndex {
479
491
dbgs () << " \n " ;
480
492
}
481
493
void print (raw_ostream &OS) const {
482
- OS << " (V=" << Val.V ->getName ()
483
- << " , zextbits=" << Val.ZExtBits
484
- << " , sextbits=" << Val.SExtBits
485
- << " , truncbits=" << Val.TruncBits
486
- << " , scale=" << Scale
487
- << " , nsw=" << IsNSW
488
- << " , negated=" << IsNegated << " )" ;
494
+ OS << " (V=" << Val.V ->getName () << " IsVScale=" << IsVScale
495
+ << " , zextbits=" << Val.ZExtBits << " , sextbits=" << Val.SExtBits
496
+ << " , truncbits=" << Val.TruncBits << " , scale=" << Scale
497
+ << " , nsw=" << IsNSW << " , negated=" << IsNegated << " )" ;
489
498
}
490
499
};
491
500
}
@@ -606,6 +615,7 @@ BasicAAResult::DecomposeGEPExpression(const Value *V, const DataLayout &DL,
606
615
for (User::const_op_iterator I = GEPOp->op_begin () + 1 , E = GEPOp->op_end ();
607
616
I != E; ++I, ++GTI) {
608
617
const Value *Index = *I;
618
+ const bool ScalableGEP = isa<ScalableVectorType>(GTI.getIndexedType ());
609
619
// Compute the (potentially symbolic) offset in bytes for this index.
610
620
if (StructType *STy = GTI.getStructTypeOrNull ()) {
611
621
// For a struct, add the member offset.
@@ -617,27 +627,18 @@ BasicAAResult::DecomposeGEPExpression(const Value *V, const DataLayout &DL,
617
627
continue ;
618
628
}
619
629
630
+ TypeSize AllocTypeSize = DL.getTypeAllocSize (GTI.getIndexedType ());
620
631
// For an array/pointer, add the element offset, explicitly scaled.
632
+ // Skip adding to constant offset if GEP index is marked as scalable
633
+ // they are handled below as variable offset
621
634
if (const ConstantInt *CIdx = dyn_cast<ConstantInt>(Index)) {
622
635
if (CIdx->isZero ())
623
636
continue ;
624
-
625
- // Don't attempt to analyze GEPs if the scalable index is not zero.
626
- TypeSize AllocTypeSize = DL.getTypeAllocSize (GTI.getIndexedType ());
627
- if (AllocTypeSize.isScalable ()) {
628
- Decomposed.Base = V;
629
- return Decomposed;
637
+ if (!ScalableGEP) {
638
+ Decomposed.Offset += AllocTypeSize.getFixedValue () *
639
+ CIdx->getValue ().sextOrTrunc (MaxIndexSize);
640
+ continue ;
630
641
}
631
-
632
- Decomposed.Offset += AllocTypeSize.getFixedValue () *
633
- CIdx->getValue ().sextOrTrunc (MaxIndexSize);
634
- continue ;
635
- }
636
-
637
- TypeSize AllocTypeSize = DL.getTypeAllocSize (GTI.getIndexedType ());
638
- if (AllocTypeSize.isScalable ()) {
639
- Decomposed.Base = V;
640
- return Decomposed;
641
642
}
642
643
643
644
GepHasConstantOffset = false ;
@@ -647,22 +648,55 @@ BasicAAResult::DecomposeGEPExpression(const Value *V, const DataLayout &DL,
647
648
unsigned Width = Index->getType ()->getIntegerBitWidth ();
648
649
unsigned SExtBits = IndexSize > Width ? IndexSize - Width : 0 ;
649
650
unsigned TruncBits = IndexSize < Width ? Width - IndexSize : 0 ;
650
- LinearExpression LE = GetLinearExpression (
651
- CastedValue (Index, 0 , SExtBits, TruncBits), DL, 0 , AC, DT);
651
+ // Scalable GEP decomposition
652
+ // Allow Scalable GEP to be decomposed in the case of
653
+ // 1. getelementptr <4 x vscale x i32> with 1st index as a constant
654
+ // 2. Index which have a leaf of @llvm.vscale
655
+ // In both cases, essentially CastedValue of VariableGEPIndex is Vscale,
656
+ // however in the 1st case, CastedValue is of type constant, hence another
657
+ // flag in VariableGEPIndex is created in this case, IsVScale If GEP is
658
+ // Scalable type, e.g. <4 x vscale x i32>, the first index will have
659
+ // vscale as a variable index, create a LE in this case
660
+ LinearExpression LE (CastedValue (Index, 0 , SExtBits, TruncBits));
661
+ if (ScalableGEP) {
662
+ if (const ConstantInt *CIdx = dyn_cast<ConstantInt>(Index)) {
663
+ LE = LinearExpression (
664
+ CastedValue (Index, 0 , SExtBits, TruncBits),
665
+ CastedValue (Index, 0 , SExtBits, TruncBits)
666
+ .evaluateWith (CIdx->getValue ()),
667
+ APInt (CastedValue (Index, 0 , SExtBits, TruncBits).getBitWidth (),
668
+ 0 ),
669
+ true );
670
+ assert (LE.Offset .isZero () && " For Scalable GEP constant first index, "
671
+ " the offset of LE should be 0" );
672
+ } else {
673
+ // if first index is not a constant, a single variable gep will
674
+ // contain 2 variables, bail in this case
675
+ Decomposed.Base = V;
676
+ return Decomposed;
677
+ }
678
+ } else
679
+ LE = GetLinearExpression (CastedValue (Index, 0 , SExtBits, TruncBits), DL,
680
+ 0 , AC, DT);
652
681
653
682
// Scale by the type size.
654
- unsigned TypeSize = AllocTypeSize.getFixedValue ();
683
+ unsigned TypeSize = AllocTypeSize.getKnownMinValue ();
655
684
LE = LE.mul (APInt (IndexSize, TypeSize), GEPOp->isInBounds ());
656
685
Decomposed.Offset += LE.Offset .sext (MaxIndexSize);
657
686
APInt Scale = LE.Scale .sext (MaxIndexSize);
687
+ bool LEhasVscale = match (LE.Val .V , m_VScale ());
658
688
659
689
// If we already had an occurrence of this index variable, merge this
660
690
// scale into it. For example, we want to handle:
661
691
// A[x][x] -> x*16 + x*4 -> x*20
662
692
// This also ensures that 'x' only appears in the index list once.
693
+ // Only add to IsVScale VariableGEPIndex if it's @llvm.vscale or gep
694
+ // vscale index
663
695
for (unsigned i = 0 , e = Decomposed.VarIndices .size (); i != e; ++i) {
664
- if (Decomposed.VarIndices [i].Val .V == LE.Val .V &&
665
- Decomposed.VarIndices [i].Val .hasSameCastsAs (LE.Val )) {
696
+ if (Decomposed.VarIndices [i].Val .hasSameCastsAs (LE.Val ) &&
697
+ ((Decomposed.VarIndices [i].IsVScale &&
698
+ (ScalableGEP || LEhasVscale)) ||
699
+ Decomposed.VarIndices [i].Val .V == LE.Val .V )) {
666
700
Scale += Decomposed.VarIndices [i].Scale ;
667
701
LE.IsNSW = false ; // We cannot guarantee nsw for the merge.
668
702
Decomposed.VarIndices .erase (Decomposed.VarIndices .begin () + i);
@@ -672,10 +706,21 @@ BasicAAResult::DecomposeGEPExpression(const Value *V, const DataLayout &DL,
672
706
673
707
// Make sure that we have a scale that makes sense for this target's
674
708
// index size.
709
+ // Only allow variableGEP decomposition for constants, in the case of
710
+ // vscale
675
711
Scale = adjustToIndexSize (Scale, IndexSize);
712
+ bool InvalidVarVScale = (ScalableGEP && LEhasVscale) ||
713
+ (ScalableGEP && !isa<ConstantInt>(LE.Val .V ));
714
+
715
+ assert (!InvalidVarVScale &&
716
+ " Variable GEP index contains VScale and another variable" );
676
717
677
718
if (!!Scale) {
678
- VariableGEPIndex Entry = {LE.Val , Scale, CxtI, LE.IsNSW ,
719
+ VariableGEPIndex Entry = {LE.Val ,
720
+ Scale,
721
+ ScalableGEP || LEhasVscale,
722
+ CxtI,
723
+ LE.IsNSW ,
679
724
/* IsNegated */ false };
680
725
Decomposed.VarIndices .push_back (Entry);
681
726
}
@@ -1058,19 +1103,15 @@ AliasResult BasicAAResult::aliasGEP(
1058
1103
1059
1104
// If an inbounds GEP would have to start from an out of bounds address
1060
1105
// for the two to alias, then we can assume noalias.
1061
- // TODO: Remove !isScalable() once BasicAA fully support scalable location
1062
- // size
1063
1106
if (*DecompGEP1.InBounds && DecompGEP1.VarIndices .empty () &&
1064
- V2Size.hasValue () && !V2Size.isScalable () &&
1065
- DecompGEP1.Offset .sge (V2Size.getValue ()) &&
1107
+ V2Size.hasValue () && DecompGEP1.Offset .sge (V2Size.getValue ().getKnownMinValue ()) &&
1066
1108
isBaseOfObject (DecompGEP2.Base ))
1067
1109
return AliasResult::NoAlias;
1068
1110
1069
1111
if (isa<GEPOperator>(V2)) {
1070
1112
// Symmetric case to above.
1071
1113
if (*DecompGEP2.InBounds && DecompGEP1.VarIndices .empty () &&
1072
- V1Size.hasValue () && !V1Size.isScalable () &&
1073
- DecompGEP1.Offset .sle (-V1Size.getValue ()) &&
1114
+ V1Size.hasValue () && DecompGEP1.Offset .sle (-V1Size.getValue ().getKnownMinValue ()) &&
1074
1115
isBaseOfObject (DecompGEP1.Base ))
1075
1116
return AliasResult::NoAlias;
1076
1117
}
@@ -1094,10 +1135,6 @@ AliasResult BasicAAResult::aliasGEP(
1094
1135
return BaseAlias;
1095
1136
}
1096
1137
1097
- // Bail on analysing scalable LocationSize
1098
- if (V1Size.isScalable () || V2Size.isScalable ())
1099
- return AliasResult::MayAlias;
1100
-
1101
1138
// If there is a constant difference between the pointers, but the difference
1102
1139
// is less than the size of the associated memory object, then we know
1103
1140
// that the objects are partially overlapping. If the difference is
@@ -1124,16 +1161,16 @@ AliasResult BasicAAResult::aliasGEP(
1124
1161
Off = -Off;
1125
1162
}
1126
1163
1127
- if (!VLeftSize.hasValue ())
1164
+ if (!VLeftSize.hasValue () || VLeftSize. isScalable () )
1128
1165
return AliasResult::MayAlias;
1129
1166
1130
- const uint64_t LSize = VLeftSize.getValue ();
1167
+ const uint64_t LSize = VLeftSize.getValue (). getKnownMinValue () ;
1131
1168
if (Off.ult (LSize)) {
1132
1169
// Conservatively drop processing if a phi was visited and/or offset is
1133
1170
// too big.
1134
1171
AliasResult AR = AliasResult::PartialAlias;
1135
1172
if (VRightSize.hasValue () && Off.ule (INT32_MAX) &&
1136
- (Off + VRightSize.getValue ()).ule (LSize)) {
1173
+ (Off + VRightSize.getValue (). getKnownMinValue () ).ule (LSize)) {
1137
1174
// Memory referenced by right pointer is nested. Save the offset in
1138
1175
// cache. Note that originally offset estimated as GEP1-V2, but
1139
1176
// AliasResult contains the shift that represents GEP1+Offset=V2.
@@ -1149,12 +1186,69 @@ AliasResult BasicAAResult::aliasGEP(
1149
1186
if (!V1Size.hasValue () || !V2Size.hasValue ())
1150
1187
return AliasResult::MayAlias;
1151
1188
1189
+ // VScale Alias Analysis
1190
+ // GEPs with Vscale will have the expression A*Vscale + B (1 variable index and constant offset)
1191
+ // The difference between two GEPs and Scalable LocationSize can then be analysed as they have the form of
1192
+ // LSize SubtractDecomposedGEP output
1193
+ // A * Vscale B * Vscale + C
1194
+ // Since VScale is strictly a positive number (Vscale >= 1), the larger GEP can be known
1195
+ // TODO: Use knowledge of vscale_range to make the analysis more accurate
1196
+ if (DecompGEP1.VarIndices .size () == 1 && DecompGEP1.VarIndices [0 ].IsVScale &&
1197
+ (V1Size.isScalable () || V2Size.isScalable ())) {
1198
+ const VariableGEPIndex &ScalableVar = DecompGEP1.VarIndices [0 ];
1199
+ bool StrictlyPos = false , StrictlyNeg = false ;
1200
+ APInt &Off = DecompGEP1.Offset ;
1201
+ if (!ScalableVar.IsNegated ) {
1202
+ if (Off.isNegative ())
1203
+ StrictlyPos = ScalableVar.Scale .ugt (Off.abs ());
1204
+ else
1205
+ StrictlyPos = true ;
1206
+ } else
1207
+ StrictlyPos = Off.isNonNegative ();
1208
+
1209
+ if (ScalableVar.IsNegated ) {
1210
+ if (Off.isNonNegative ())
1211
+ StrictlyNeg = Off.ult (ScalableVar.Scale .abs ());
1212
+ else
1213
+ StrictlyNeg = true ;
1214
+ } else
1215
+ StrictlyNeg = Off.isNegative ();
1216
+
1217
+ if (StrictlyPos || StrictlyNeg) {
1218
+ LocationSize VLeftSize = V2Size;
1219
+ LocationSize VRightSize = V1Size;
1220
+ const bool Swapped = StrictlyNeg;
1221
+
1222
+ if (Swapped) {
1223
+ std::swap (VLeftSize, VRightSize);
1224
+ Off = -Off;
1225
+ }
1226
+
1227
+ const uint64_t LSize = VLeftSize.getValue ().getKnownMinValue ();
1228
+ if (VLeftSize.isScalable () && ScalableVar.Scale .ult (LSize) &&
1229
+ (ScalableVar.Scale + DecompGEP1.Offset ).ult (LSize))
1230
+ return AliasResult::PartialAlias;
1231
+
1232
+ if ((ScalableVar.Scale .uge (LSize) && VLeftSize.isScalable ()) ||
1233
+ ((ScalableVar.Scale + DecompGEP1.Offset ).uge (LSize) &&
1234
+ !VLeftSize.isScalable ()))
1235
+ return AliasResult::NoAlias;
1236
+ }
1237
+ }
1238
+
1239
+ // Bail on Scalable location size from now onwards
1240
+ if (V1Size.isScalable () || V2Size.isScalable ())
1241
+ return AliasResult::MayAlias;
1242
+
1152
1243
APInt GCD;
1153
1244
ConstantRange OffsetRange = ConstantRange (DecompGEP1.Offset );
1154
1245
for (unsigned i = 0 , e = DecompGEP1.VarIndices .size (); i != e; ++i) {
1155
1246
const VariableGEPIndex &Index = DecompGEP1.VarIndices [i];
1156
1247
const APInt &Scale = Index.Scale ;
1157
1248
APInt ScaleForGCD = Scale;
1249
+ assert ((!Index.IsVScale || match (Index.Val .V , m_VScale ()) ||
1250
+ isa<ConstantInt>(Index.Val .V )) &&
1251
+ " Not allowed to have non-constant values if IsVScale is set" );
1158
1252
if (!Index.IsNSW )
1159
1253
ScaleForGCD =
1160
1254
APInt::getOneBitSet (Scale.getBitWidth (), Scale.countr_zero ());
@@ -1727,7 +1821,12 @@ void BasicAAResult::subtractDecomposedGEPs(DecomposedGEP &DestGEP,
1727
1821
bool Found = false ;
1728
1822
for (auto I : enumerate(DestGEP.VarIndices )) {
1729
1823
VariableGEPIndex &Dest = I.value ();
1730
- if (!isValueEqualInPotentialCycles (Dest.Val .V , Src.Val .V , AAQI) ||
1824
+ if (Dest.IsVScale != Src.IsVScale )
1825
+ continue ;
1826
+ const bool SrcDestAreVScale = Dest.IsVScale && Src.IsVScale ;
1827
+ // Suppress base value checks if Src and Dst are of constant VScale
1828
+ if ((!SrcDestAreVScale &&
1829
+ !isValueEqualInPotentialCycles (Dest.Val .V , Src.Val .V , AAQI)) ||
1731
1830
!Dest.Val .hasSameCastsAs (Src.Val ))
1732
1831
continue ;
1733
1832
@@ -1752,7 +1851,11 @@ void BasicAAResult::subtractDecomposedGEPs(DecomposedGEP &DestGEP,
1752
1851
1753
1852
// If we didn't consume this entry, add it to the end of the Dest list.
1754
1853
if (!Found) {
1755
- VariableGEPIndex Entry = {Src.Val , Src.Scale , Src.CxtI , Src.IsNSW ,
1854
+ VariableGEPIndex Entry = {Src.Val ,
1855
+ Src.Scale ,
1856
+ Src.IsVScale ,
1857
+ Src.CxtI ,
1858
+ Src.IsNSW ,
1756
1859
/* IsNegated */ true };
1757
1860
DestGEP.VarIndices .push_back (Entry);
1758
1861
}
0 commit comments