#include "llvm/IR/Argument.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/Constant.h"
+#include "llvm/IR/ConstantRange.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
return AliasResult::NoAlias;
if (V1Size.hasValue() && V2Size.hasValue()) {
- // Try to determine whether abs(VarIndex) > 0.
+ // Try to determine the range of values for VarIndex.
+ // VarIndexRange is such that:
+ // (VarIndex <= -MinAbsVarIndex || MinAbsVarIndex <= VarIndex) &&
+ // VarIndexRange.contains(VarIndex)
Optional<APInt> MinAbsVarIndex;
+ Optional<ConstantRange> VarIndexRange;
if (DecompGEP1.VarIndices.size() == 1) {
- // VarIndex = Scale*V. If V != 0 then abs(VarIndex) >= abs(Scale).
+ // VarIndex = Scale*V.
const VariableGEPIndex &Var = DecompGEP1.VarIndices[0];
- if (isKnownNonZero(Var.V, DL, 0, &AC, Var.CxtI, DT))
+ if (isKnownNonZero(Var.V, DL, 0, &AC, Var.CxtI, DT)) {
+ // If V != 0 then abs(VarIndex) >= abs(Scale).
MinAbsVarIndex = Var.Scale.abs();
+ }
+ ConstantRange R = computeConstantRange(Var.V, true, &AC, Var.CxtI);
+ if (!R.isFullSet() && !R.isEmptySet()) {
+ if (Var.SExtBits)
+ R = R.signExtend(R.getBitWidth() + Var.SExtBits);
+ if (Var.ZExtBits)
+ R = R.zeroExtend(R.getBitWidth() + Var.ZExtBits);
+ VarIndexRange = R.sextOrTrunc(Var.Scale.getBitWidth())
+ .multiply(ConstantRange(Var.Scale));
+ }
} else if (DecompGEP1.VarIndices.size() == 2) {
// VarIndex = Scale*V0 + (-Scale)*V1.
// If V0 != V1 then abs(VarIndex) >= abs(Scale).
// The constant offset will have added at least +/-MinAbsVarIndex to it.
APInt OffsetLo = DecompGEP1.Offset - *MinAbsVarIndex;
APInt OffsetHi = DecompGEP1.Offset + *MinAbsVarIndex;
- // Check that an access at OffsetLo or lower, and an access at OffsetHi
- // or higher both do not alias.
+ // We know that Offset <= OffsetLo || Offset >= OffsetHi
if (OffsetLo.isNegative() && (-OffsetLo).uge(V1Size.getValue()) &&
OffsetHi.isNonNegative() && OffsetHi.uge(V2Size.getValue()))
return AliasResult::NoAlias;
}
+
+ if (VarIndexRange) {
+ ConstantRange OffsetRange =
+ VarIndexRange->add(ConstantRange(DecompGEP1.Offset));
+
+ // We know that Offset >= MinOffset.
+ // (MinOffset >= V2Size) => (Offset >= V2Size) => NoAlias.
+ if (OffsetRange.getSignedMin().sge(V2Size.getValue()))
+ return AliasResult::NoAlias;
+
+ // We know that Offset <= MaxOffset.
+ // (MaxOffset <= -V1Size) => (Offset <= -V1Size) => NoAlias.
+ if (OffsetRange.getSignedMax().sle(-V1Size.getValue()))
+ return AliasResult::NoAlias;
+ }
}
if (constantOffsetHeuristic(DecompGEP1, V1Size, V2Size, &AC, DT))
--- /dev/null
+; RUN: opt < %s -basic-aa -aa-eval -print-all-alias-modref-info -disable-output 2>&1 | FileCheck %s
+
+%struct.S = type { i32, [2 x i32], i32 }
+%struct.S2 = type { i32, [4 x i32], [4 x i32] }
+
+; CHECK: Function: t1
+; CHECK: NoAlias: i32* %gep1, i32* %gep2
+define void @t1(%struct.S* %s) {
+ %gep1 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 1, i32 1
+ %gep2 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 1, i32 0
+ ret void
+}
+
+; CHECK: Function: t2_fwd
+; CHECK: MayAlias: i32* %gep1, i32* %gep2
+define void @t2_fwd(%struct.S* %s, i32* %q) {
+ %in_array = load i32, i32* %q, !range !0
+ %gep1 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 1, i32 %in_array
+ %gep2 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 1, i32 0
+ ret void
+}
+
+; CHECK: Function: t2_rev
+; CHECK: MayAlias: i32* %gep1, i32* %gep2
+define void @t2_rev(%struct.S* %s, i32* %q) {
+ %in_array = load i32, i32* %q, !range !0
+ %gep1 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 1, i32 0
+ %gep2 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 1, i32 %in_array
+ ret void
+}
+
+; CHECK: Function: t3_fwd
+; CHECK: NoAlias: i32* %gep1, i32* %gep2
+define void @t3_fwd(%struct.S* %s, i32* %q) {
+ %knownzero = load i32, i32* %q, !range !1
+ %gep1 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 1, i32 %knownzero
+ %gep2 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 1, i32 1
+ ret void
+}
+
+; CHECK: Function: t3_rev
+; CHECK: NoAlias: i32* %gep1, i32* %gep2
+define void @t3_rev(%struct.S* %s, i32* %q) {
+ %knownzero = load i32, i32* %q, !range !1
+ %gep1 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 1, i32 1
+ %gep2 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 1, i32 %knownzero
+ ret void
+}
+
+; CHECK: Function: member_after
+; CHECK: NoAlias: i32* %gep1, i32* %gep2
+define void @member_after(%struct.S* %s, i32* %q) {
+ %in_array = load i32, i32* %q, !range !0
+ %gep1 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 1, i32 %in_array
+ %gep2 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 2
+ ret void
+}
+
+; CHECK: Function: member_after_rev
+; CHECK: NoAlias: i32* %gep1, i32* %gep2
+define void @member_after_rev(%struct.S* %s, i32* %q) {
+ %in_array = load i32, i32* %q, !range !0
+ %gep2 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 2
+ %gep1 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 1, i32 %in_array
+ ret void
+}
+
+; CHECK: Function: member_before
+; CHECK: NoAlias: i32* %gep1, i32* %gep2
+define void @member_before(%struct.S* %s, i32* %q) {
+ %in_array = load i32, i32* %q, !range !0
+ %gep1 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 1, i32 %in_array
+ %gep2 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 0
+ ret void
+}
+
+; CHECK: Function: member_before_rev
+; CHECK: NoAlias: i32* %gep1, i32* %gep2
+define void @member_before_rev(%struct.S* %s, i32* %q) {
+ %in_array = load i32, i32* %q, !range !0
+ %gep2 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 0
+ %gep1 = getelementptr inbounds %struct.S, %struct.S* %s, i64 0, i32 1, i32 %in_array
+ ret void
+}
+
+; CHECK: Function: t5
+; CHECK-NEXT: MayAlias: %struct.S2* %s, i32* %q
+; CHECK-NEXT: MayAlias: %struct.S2* %s, i32* %gep1
+; CHECK-NEXT: MayAlias: i32* %gep1, i32* %q
+; CHECK-NEXT: PartialAlias (off 4): %struct.S2* %s, i32* %gep2
+; CHECK-NEXT: MayAlias: i32* %gep2, i32* %q
+; CHECK-NEXT: NoAlias: i32* %gep1, i32* %gep2
+define void @t5(%struct.S2* %s, i32* %q) {
+ %in_array = load i32, i32* %q, !range !3
+ %gep1 = getelementptr inbounds %struct.S2, %struct.S2* %s, i64 0, i32 2, i32 %in_array
+ %gep2 = getelementptr inbounds %struct.S2, %struct.S2* %s, i64 0, i32 1, i32 0
+ ret void
+}
+
+; CHECK: Function: t6
+; CHECK-NEXT: MayAlias: %struct.S2* %s, i32* %q
+; CHECK-NEXT: MayAlias: %struct.S2* %s, i32* %gep1
+; CHECK-NEXT: MayAlias: i32* %gep1, i32* %q
+; CHECK-NEXT: PartialAlias (off 16): %struct.S2* %s, i32* %gep2
+; CHECK-NEXT: MayAlias: i32* %gep2, i32* %q
+; CHECK-NEXT: MayAlias: i32* %gep1, i32* %gep2
+define void @t6(%struct.S2* %s, i32* %q) {
+ %in_array = load i32, i32* %q, !range !3
+ %gep1 = getelementptr inbounds %struct.S2, %struct.S2* %s, i64 0, i32 2, i32 %in_array
+ %gep2 = getelementptr inbounds %struct.S2, %struct.S2* %s, i64 0, i32 1, i32 3
+ ret void
+}
+
+; CHECK: Function: t7
+; CHECK-NEXT: MayAlias: %struct.S2* %s, i32* %q
+; CHECK-NEXT: MayAlias: %struct.S2* %s, i32* %gep1
+; CHECK-NEXT: MayAlias: i32* %gep1, i32* %q
+; CHECK-NEXT: PartialAlias (off 20): %struct.S2* %s, i32* %gep2
+; CHECK-NEXT: MayAlias: i32* %gep2, i32* %q
+; CHECK-NEXT: NoAlias: i32* %gep1, i32* %gep2
+define void @t7(%struct.S2* %s, i32* %q) {
+ %in_array = load i32, i32* %q, !range !4
+ %gep1 = getelementptr inbounds %struct.S2, %struct.S2* %s, i64 0, i32 2, i32 %in_array
+ %gep2 = getelementptr inbounds %struct.S2, %struct.S2* %s, i64 0, i32 2, i32 0
+ ret void
+}
+
+; CHECK: Function: t8
+; CHECK-NEXT: MayAlias: %struct.S2* %s, i32* %q
+; CHECK-NEXT: MayAlias: %struct.S2* %s, i32* %gep1
+; CHECK-NEXT: MayAlias: i32* %gep1, i32* %q
+; CHECK-NEXT: PartialAlias (off 24): %struct.S2* %s, i32* %gep2
+; CHECK-NEXT: MayAlias: i32* %gep2, i32* %q
+; CHECK-NEXT: MayAlias: i32* %gep1, i32* %gep2
+define void @t8(%struct.S2* %s, i32* %q) {
+ %in_array = load i32, i32* %q, !range !4
+ %gep1 = getelementptr inbounds %struct.S2, %struct.S2* %s, i64 0, i32 2, i32 %in_array
+ %gep2 = getelementptr inbounds %struct.S2, %struct.S2* %s, i64 0, i32 2, i32 1
+ ret void
+}
+
+; CHECK: Function: t9
+; CHECK-NEXT: MayAlias: %struct.S2* %s, i32* %q
+; CHECK-NEXT: MayAlias: %struct.S2* %s, i32* %gep1
+; CHECK-NEXT: MayAlias: i32* %gep1, i32* %q
+; CHECK-NEXT: PartialAlias (off 20): %struct.S2* %s, i32* %gep2
+; CHECK-NEXT: MayAlias: i32* %gep2, i32* %q
+; CHECK-NEXT: NoAlias: i32* %gep1, i32* %gep2
+define void @t9(%struct.S2* %s, i32* %q) {
+ %in_array = load i32, i32* %q, !range !5
+ %gep1 = getelementptr inbounds %struct.S2, %struct.S2* %s, i64 0, i32 1, i32 %in_array
+ %gep2 = getelementptr inbounds %struct.S2, %struct.S2* %s, i64 0, i32 2, i32 0
+ ret void
+}
+
+; CHECK: Function: t10
+; CHECK-NEXT: MayAlias: %struct.S2* %s, i32* %q
+; CHECK-NEXT: MayAlias: %struct.S2* %s, i32* %gep1
+; CHECK-NEXT: MayAlias: i32* %gep1, i32* %q
+; CHECK-NEXT: PartialAlias (off 4): %struct.S2* %s, i32* %gep2
+; CHECK-NEXT: MayAlias: i32* %gep2, i32* %q
+; CHECK-NEXT: MayAlias: i32* %gep1, i32* %gep2
+define void @t10(%struct.S2* %s, i32* %q) {
+ %in_array = load i32, i32* %q, !range !5
+ %gep1 = getelementptr inbounds %struct.S2, %struct.S2* %s, i64 0, i32 2, i32 %in_array
+ %gep2 = getelementptr inbounds %struct.S2, %struct.S2* %s, i64 0, i32 1, i32 0
+ ret void
+}
+
+; CHECK: Function: zeroext_index
+; CHECK-NEXT: MayAlias: [256 x i32]* %s, i8* %q
+; CHECK-NEXT: MayAlias: [256 x i32]* %s, i32* %gep
+; CHECK-NEXT: MayAlias: i32* %gep, i8* %q
+define void @zeroext_index([256 x i32]* %s, i8* %q) {
+ %a = load i8, i8* %q, !range !6
+ %in_array = zext i8 %a to i32
+ %gep = getelementptr inbounds [256 x i32], [256 x i32]* %s, i64 0, i32 %in_array
+ ret void
+}
+
+
+!0 = !{ i32 0, i32 2 }
+!1 = !{ i32 0, i32 1 }
+!2 = !{ i32 1, i32 2 }
+!3 = !{ i32 -2, i32 0 }
+!4 = !{ i32 1, i32 536870911 }
+!5 = !{ i32 -536870911, i32 4 }
+!6 = !{ i8 -2, i8 0 }