}
static const MDNode *createAccessTag(const MDNode *AccessType) {
+ // If there is no access type or the access type is the root node, then
+ // we don't have any useful access tag to return.
+ if (!AccessType || AccessType->getNumOperands() < 2)
+ return nullptr;
+
Type *Int64 = IntegerType::get(AccessType->getContext(), 64);
auto *ImmutabilityFlag = ConstantAsMetadata::get(ConstantInt::get(Int64, 0));
Metadata *Ops[] = {const_cast<MDNode*>(AccessType),
assert(isStructPathTBAA(B) && "Access B is not struct-path aware!");
TBAAStructTagNode TagA(A), TagB(B);
+ const MDNode *CommonType = getLeastCommonType(TagA.getAccessType(),
+ TagB.getAccessType());
+ if (GenericTag)
+ *GenericTag = createAccessTag(CommonType);
// TODO: We need to check if AccessType of TagA encloses AccessType of
// TagB to support aggregate AccessType. If yes, return true.
- const MDNode *BaseA = TagA.getBaseType();
- const MDNode *BaseB = TagB.getBaseType();
-
// Climb the type DAG from base type of A to see if we reach base type of B.
uint64_t OffsetA;
- if (findAccessType(TagA, BaseB, OffsetA)) {
- if (GenericTag)
- *GenericTag = createAccessTag(TagB.getAccessType());
+ if (findAccessType(TagA, TagB.getBaseType(), OffsetA))
return OffsetA == TagB.getOffset();
- }
// Climb the type DAG from base type of B to see if we reach base type of A.
uint64_t OffsetB;
- if (findAccessType(TagB, BaseA, OffsetB)) {
- if (GenericTag)
- *GenericTag = createAccessTag(TagA.getAccessType());
+ if (findAccessType(TagB, TagA.getBaseType(), OffsetB))
return OffsetB == TagA.getOffset();
- }
-
- // If neither node is an ancestor of the other, then try to find the type
- // that is common to both the final access types.
- const MDNode *CommonType = getLeastCommonType(TagA.getAccessType(),
- TagB.getAccessType());
-
- // If there is no common type or the only common type is the root node, then
- // we don't have any useful generic access tag to return.
- if (GenericTag)
- *GenericTag = !CommonType || CommonType->getNumOperands() < 2 ?
- nullptr : createAccessTag(CommonType);
- // If they have different roots, they're part of different potentially
- // unrelated type systems, so we must be conservative.
+ // If the final access types have different roots, they're part of different
+ // potentially unrelated type systems, so we must be conservative.
if (!CommonType)
return true;
--- /dev/null
+; RUN: opt -mtriple=x86_64-unknown-linux-gnu -load-store-vectorizer -S < %s | \
+; RUN: FileCheck %s
+;
+; The GPU Load & Store Vectorizer may merge differently-typed accesses into a
+; single instruction. This test checks that we merge TBAA tags for such
+; accesses correctly.
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+; struct S {
+; float f;
+; int i;
+; };
+%struct.S = type { float, i32 }
+
+; float foo(S *p) {
+; p->f -= 1;
+; p->i -= 1;
+; return p->f;
+; }
+define float @foo(%struct.S* %p) {
+entry:
+; CHECK-LABEL: foo
+; CHECK: load <2 x i32>, {{.*}}, !tbaa [[TAG_char:!.*]]
+; CHECK: store <2 x i32> {{.*}}, !tbaa [[TAG_char]]
+ %f = getelementptr inbounds %struct.S, %struct.S* %p, i64 0, i32 0
+ %0 = load float, float* %f, align 4, !tbaa !2
+ %sub = fadd float %0, -1.000000e+00
+ store float %sub, float* %f, align 4, !tbaa !2
+ %i = getelementptr inbounds %struct.S, %struct.S* %p, i64 0, i32 1
+ %1 = load i32, i32* %i, align 4, !tbaa !8
+ %sub1 = add nsw i32 %1, -1
+ store i32 %sub1, i32* %i, align 4, !tbaa !8
+ ret float %sub
+}
+
+!2 = !{!3, !4, i64 0}
+!3 = !{!"_ZTS1S", !4, i64 0, !7, i64 4}
+!4 = !{!"float", !5, i64 0}
+!5 = !{!"omnipotent char", !6, i64 0}
+!6 = !{!"Simple C++ TBAA"}
+!7 = !{!"int", !5, i64 0}
+!8 = !{!3, !7, i64 4}
+
+; CHECK-DAG: [[TYPE_char:!.*]] = !{!"omnipotent char", {{.*}}, i64 0}
+; CHECK-FAG: [[TAG_char]] = !{[[TYPE_char]], [[TYPE_char]], i64 0}