llvm.org GIT mirror llvm / f27bcb0
[DSE] Merge stores when the later store only writes to memory locations the early store also wrote to. Summary: This fixes PR31777. If both stores' values are ConstantInt, we merge the two stores (shifting the smaller store appropriately) and replace the earlier (and larger) store with an updated constant. In the future we should also support vectors of integers. And maybe float/double if we can. Reviewers: hfinkel, junbuml, jfb, RKSimon, bkramer Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D30703 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@310055 91177308-0d34-0410-b5e6-96231b3b80d8 Filipe Cabecinhas 2 years ago
5 changed file(s) with 480 addition(s) and 5 deletion(s). Raw diff Collapse all Expand all
3333 #include "llvm/IR/GlobalVariable.h"
3434 #include "llvm/IR/Instructions.h"
3535 #include "llvm/IR/IntrinsicInst.h"
36 #include "llvm/IR/LLVMContext.h"
3637 #include "llvm/Pass.h"
3738 #include "llvm/Support/CommandLine.h"
3839 #include "llvm/Support/Debug.h"
4849 STATISTIC(NumFastStores, "Number of stores deleted");
4950 STATISTIC(NumFastOther , "Number of other instrs removed");
5051 STATISTIC(NumCompletePartials, "Number of stores dead by later partials");
52 STATISTIC(NumModifiedStores, "Number of stores modified");
5153
5254 static cl::opt
5355 EnablePartialOverwriteTracking("enable-dse-partial-overwrite-tracking",
5456 cl::init(true), cl::Hidden,
5557 cl::desc("Enable partial-overwrite tracking in DSE"));
58
59 static cl::opt
60 EnablePartialStoreMerging("enable-dse-partial-store-merging",
61 cl::init(true), cl::Hidden,
62 cl::desc("Enable partial store merging in DSE"));
5663
5764
5865 //===----------------------------------------------------------------------===//
286293 }
287294
288295 namespace {
289 enum OverwriteResult { OW_Begin, OW_Complete, OW_End, OW_Unknown };
296 enum OverwriteResult {
297 OW_Begin,
298 OW_Complete,
299 OW_End,
300 OW_PartialEarlierWithFullLater,
301 OW_Unknown
302 };
290303 }
291304
292305 /// Return 'OW_Complete' if a store to the 'Later' location completely
293306 /// overwrites a store to the 'Earlier' location, 'OW_End' if the end of the
294307 /// 'Earlier' location is completely overwritten by 'Later', 'OW_Begin' if the
295 /// beginning of the 'Earlier' location is overwritten by 'Later', or
296 /// 'OW_Unknown' if nothing can be determined.
308 /// beginning of the 'Earlier' location is overwritten by 'Later'.
309 /// 'OW_PartialEarlierWithFullLater' means that an earlier (big) store was
310 /// overwritten by a latter (smaller) store which doesn't write outside the big
311 /// store's memory locations. Returns 'OW_Unknown' if nothing can be determined.
297312 static OverwriteResult isOverwrite(const MemoryLocation &Later,
298313 const MemoryLocation &Earlier,
299314 const DataLayout &DL,
424439 ++NumCompletePartials;
425440 return OW_Complete;
426441 }
442 }
443
444 // Check for an earlier store which writes to all the memory locations that
445 // the later store writes to.
446 if (EnablePartialStoreMerging && LaterOff >= EarlierOff &&
447 int64_t(EarlierOff + Earlier.Size) > LaterOff &&
448 uint64_t(LaterOff - EarlierOff) + Later.Size <= Earlier.Size) {
449 DEBUG(dbgs() << "DSE: Partial overwrite an earlier load [" << EarlierOff
450 << ", " << int64_t(EarlierOff + Earlier.Size)
451 << ") by a later store [" << LaterOff << ", "
452 << int64_t(LaterOff + Later.Size) << ")\n");
453 // TODO: Maybe come up with a better name?
454 return OW_PartialEarlierWithFullLater;
427455 }
428456
429457 // Another interesting case is if the later store overwrites the end of the
10931121 // If we find a write that is a) removable (i.e., non-volatile), b) is
10941122 // completely obliterated by the store to 'Loc', and c) which we know that
10951123 // 'Inst' doesn't load from, then we can remove it.
1124 // Also try to merge two stores if a latter one only touches memory
1125 // written to by the earlier one.
10961126 if (isRemovable(DepWrite) &&
10971127 !isPossibleSelfRead(Inst, Loc, DepWrite, *TLI, *AA)) {
10981128 int64_t InstWriteOffset, DepWriteOffset;
11221152 bool IsOverwriteEnd = (OR == OW_End);
11231153 MadeChange |= tryToShorten(DepWrite, DepWriteOffset, EarlierSize,
11241154 InstWriteOffset, LaterSize, IsOverwriteEnd);
1155 } else if (EnablePartialStoreMerging &&
1156 OR == OW_PartialEarlierWithFullLater) {
1157 auto *Earlier = dyn_cast(DepWrite);
1158 auto *Later = dyn_cast(Inst);
1159 if (Earlier && isa(Earlier->getValueOperand()) &&
1160 Later && isa(Later->getValueOperand())) {
1161 // If the store we find is:
1162 // a) partially overwritten by the store to 'Loc'
1163 // b) the latter store is fully contained in the earlier one and
1164 // c) They both have a contant value
1165 // Merge the two stores, replacing the earlier store's value with a
1166 // merge of both values.
1167 // TODO: Deal with other constant types (vectors, etc), and probably
1168 // some mem intrinsics (if needed)
1169
1170 APInt EarlierValue =
1171 cast(Earlier->getValueOperand())->getValue();
1172 APInt LaterValue =
1173 cast(Later->getValueOperand())->getValue();
1174 unsigned LaterBits = LaterValue.getBitWidth();
1175 assert(EarlierValue.getBitWidth() > LaterValue.getBitWidth());
1176 LaterValue = LaterValue.zext(EarlierValue.getBitWidth());
1177
1178 // Offset of the smaller store inside the larger store
1179 unsigned BitOffsetDiff = (InstWriteOffset - DepWriteOffset) * 8;
1180 unsigned LShiftAmount =
1181 DL.isBigEndian()
1182 ? EarlierValue.getBitWidth() - BitOffsetDiff - LaterBits
1183 : BitOffsetDiff;
1184 APInt Mask =
1185 APInt::getBitsSet(EarlierValue.getBitWidth(), LShiftAmount,
1186 LShiftAmount + LaterBits);
1187 // Clear the bits we'll be replacing, then OR with the smaller
1188 // store, shifted appropriately.
1189 APInt Merged =
1190 (EarlierValue & ~Mask) | (LaterValue << LShiftAmount);
1191 DEBUG(dbgs() << "DSE: Merge Stores:\n Earlier: " << *DepWrite
1192 << "\n Later: " << *Inst
1193 << "\n Merged Value: " << Merged << '\n');
1194
1195 auto *SI = new StoreInst(
1196 ConstantInt::get(Earlier->getValueOperand()->getType(), Merged),
1197 Earlier->getPointerOperand(), false, Earlier->getAlignment(),
1198 Earlier->getOrdering(), Earlier->getSyncScopeID(), DepWrite);
1199
1200 unsigned MDToKeep[] = {LLVMContext::MD_dbg, LLVMContext::MD_tbaa,
1201 LLVMContext::MD_alias_scope,
1202 LLVMContext::MD_noalias,
1203 LLVMContext::MD_nontemporal};
1204 SI->copyMetadata(*DepWrite, MDToKeep);
1205 ++NumModifiedStores;
1206
1207 // Remove earlier, wider, store
1208 size_t Idx = InstrOrdering.lookup(DepWrite);
1209 InstrOrdering.erase(DepWrite);
1210 InstrOrdering.insert(std::make_pair(SI, Idx));
1211
1212 // Delete the old stores and now-dead instructions that feed them.
1213 deleteDeadInstruction(Inst, &BBI, *MD, *TLI, IOL, &InstrOrdering);
1214 deleteDeadInstruction(DepWrite, &BBI, *MD, *TLI, IOL,
1215 &InstrOrdering);
1216 MadeChange = true;
1217
1218 //// We erased DepWrite; start over.
1219 InstDep = MD->getDependency(SI);
1220 continue;
1221 }
11251222 }
11261223 }
11271224
None ; RUN: opt < %s -basicaa -dse -S | FileCheck %s
0 ; RUN: opt < %s -basicaa -dse -enable-dse-partial-store-merging=false -S | FileCheck %s
11 target datalayout = "E-p:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128"
22
33 ; Ensure that the dead store is deleted in this case. It is wholely
None ; RUN: opt -S -dse < %s | FileCheck %s
0 ; RUN: opt -S -dse -enable-dse-partial-store-merging=false < %s | FileCheck %s
11 target datalayout = "E-m:e-i64:64-n32:64"
22 target triple = "powerpc64-bgq-linux"
33
0 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
1 ; RUN: opt -dse -enable-dse-partial-store-merging -S < %s | FileCheck %s
2 target datalayout = "E-m:e-i64:64-i128:128-n32:64-S128"
3
4 define void @byte_by_byte_replacement(i32 *%ptr) {
5 ; CHECK-LABEL: @byte_by_byte_replacement(
6 ; CHECK-NEXT: entry:
7 ; CHECK-NEXT: store i32 151653132, i32* [[PTR:%.*]]
8 ; CHECK-NEXT: ret void
9 ;
10 entry:
11 ;; This store's value should be modified as it should be better to use one
12 ;; larger store than several smaller ones.
13 ;; store will turn into 0x090A0B0C == 151653132
14 store i32 305419896, i32* %ptr ; 0x12345678
15 %bptr = bitcast i32* %ptr to i8*
16 %bptr1 = getelementptr inbounds i8, i8* %bptr, i64 1
17 %bptr2 = getelementptr inbounds i8, i8* %bptr, i64 2
18 %bptr3 = getelementptr inbounds i8, i8* %bptr, i64 3
19
20 ;; We should be able to merge these four stores with the i32 above
21 ; value (and bytes) stored before ; 0x12345678
22 store i8 9, i8* %bptr ; 09
23 store i8 10, i8* %bptr1 ; 0A
24 store i8 11, i8* %bptr2 ; 0B
25 store i8 12, i8* %bptr3 ; 0C
26 ; 0x090A0B0C
27
28 ret void
29 }
30
31 define void @word_replacement(i64 *%ptr) {
32 ; CHECK-LABEL: @word_replacement(
33 ; CHECK-NEXT: entry:
34 ; CHECK-NEXT: store i64 72638273700655232, i64* [[PTR:%.*]]
35 ; CHECK-NEXT: ret void
36 ;
37 entry:
38 store i64 72623859790382856, i64* %ptr ; 0x0102030405060708
39
40 %wptr = bitcast i64* %ptr to i16*
41 %wptr1 = getelementptr inbounds i16, i16* %wptr, i64 1
42 %wptr2 = getelementptr inbounds i16, i16* %wptr, i64 2
43 %wptr3 = getelementptr inbounds i16, i16* %wptr, i64 3
44
45 ;; We should be able to merge these two stores with the i64 one above
46 ; value (and bytes) stored before ; 0x0102030405060708
47 store i16 4128, i16* %wptr1 ; 1020
48 store i16 28800, i16* %wptr3 ; 7080
49 ; 0x0102102005067080
50
51 ret void
52 }
53
54
55 define void @differently_sized_replacements(i64 *%ptr) {
56 ; CHECK-LABEL: @differently_sized_replacements(
57 ; CHECK-NEXT: entry:
58 ; CHECK-NEXT: store i64 289077004501059343, i64* [[PTR:%.*]]
59 ; CHECK-NEXT: ret void
60 ;
61 entry:
62 store i64 579005069656919567, i64* %ptr ; 0x08090a0b0c0d0e0f
63
64 %bptr = bitcast i64* %ptr to i8*
65 %bptr6 = getelementptr inbounds i8, i8* %bptr, i64 6
66 %wptr = bitcast i64* %ptr to i16*
67 %wptr2 = getelementptr inbounds i16, i16* %wptr, i64 2
68 %dptr = bitcast i64* %ptr to i32*
69
70 ;; We should be able to merge all these stores with the i64 one above
71 ; value (and bytes) stored before ; 0x08090a0b0c0d0e0f
72 store i8 7, i8* %bptr6 ; 07
73 store i16 1541, i16* %wptr2 ; 0605
74 store i32 67305985, i32* %dptr ; 04030201
75 ; 0x040302010605070f
76 ret void
77 }
78
79
80 define void @multiple_replacements_to_same_byte(i64 *%ptr) {
81 ; CHECK-LABEL: @multiple_replacements_to_same_byte(
82 ; CHECK-NEXT: entry:
83 ; CHECK-NEXT: store i64 289077004602248719, i64* [[PTR:%.*]]
84 ; CHECK-NEXT: ret void
85 ;
86 entry:
87 store i64 579005069656919567, i64* %ptr ; 0x08090a0b0c0d0e0f
88
89 %bptr = bitcast i64* %ptr to i8*
90 %bptr3 = getelementptr inbounds i8, i8* %bptr, i64 3
91 %wptr = bitcast i64* %ptr to i16*
92 %wptr1 = getelementptr inbounds i16, i16* %wptr, i64 1
93 %dptr = bitcast i64* %ptr to i32*
94
95 ;; We should be able to merge all these stores with the i64 one above
96 ; value (and bytes) stored before ; 0x08090a0b0c0d0e0f
97 store i8 7, i8* %bptr3 ; 07
98 store i16 1541, i16* %wptr1 ; 0605
99 store i32 67305985, i32* %dptr ; 04030201
100 ; 0x040302010c0d0e0f
101 ret void
102 }
103
104 define void @merged_merges(i64 *%ptr) {
105 ; CHECK-LABEL: @merged_merges(
106 ; CHECK-NEXT: entry:
107 ; CHECK-NEXT: store i64 289081428418563599, i64* [[PTR:%.*]]
108 ; CHECK-NEXT: ret void
109 ;
110 entry:
111 store i64 579005069656919567, i64* %ptr ; 0x08090a0b0c0d0e0f
112
113 %bptr = bitcast i64* %ptr to i8*
114 %bptr3 = getelementptr inbounds i8, i8* %bptr, i64 3
115 %wptr = bitcast i64* %ptr to i16*
116 %wptr1 = getelementptr inbounds i16, i16* %wptr, i64 1
117 %dptr = bitcast i64* %ptr to i32*
118
119 ;; We should be able to merge all these stores with the i64 one above
120 ; value (not bytes) stored before ; 0x08090a0b0c0d0e0f
121 store i32 67305985, i32* %dptr ; 04030201
122 store i16 1541, i16* %wptr1 ; 0605
123 store i8 7, i8* %bptr3 ; 07
124 ; 0x040306070c0d0e0f
125 ret void
126 }
127
128 define signext i8 @shouldnt_merge_since_theres_a_full_overlap(i64 *%ptr) {
129 ; CHECK-LABEL: @shouldnt_merge_since_theres_a_full_overlap(
130 ; CHECK-NEXT: entry:
131 ; CHECK-NEXT: [[BPTR:%.*]] = bitcast i64* [[PTR:%.*]] to i8*
132 ; CHECK-NEXT: [[BPTRM1:%.*]] = getelementptr inbounds i8, i8* [[BPTR]], i64 -1
133 ; CHECK-NEXT: [[BPTR3:%.*]] = getelementptr inbounds i8, i8* [[BPTR]], i64 3
134 ; CHECK-NEXT: [[DPTR:%.*]] = bitcast i8* [[BPTRM1]] to i32*
135 ; CHECK-NEXT: [[QPTR:%.*]] = bitcast i8* [[BPTR3]] to i64*
136 ; CHECK-NEXT: store i32 1234, i32* [[DPTR]], align 1
137 ; CHECK-NEXT: store i64 5678, i64* [[QPTR]], align 1
138 ; CHECK-NEXT: ret i8 0
139 ;
140 entry:
141
142 store i64 0, i64* %ptr
143
144 %bptr = bitcast i64* %ptr to i8*
145 %bptrm1 = getelementptr inbounds i8, i8* %bptr, i64 -1
146 %bptr3 = getelementptr inbounds i8, i8* %bptr, i64 3
147 %dptr = bitcast i8* %bptrm1 to i32*
148 %qptr = bitcast i8* %bptr3 to i64*
149
150 store i32 1234, i32* %dptr, align 1
151 store i64 5678, i64* %qptr, align 1
152
153 ret i8 0
154 }
155
156 ;; Test case from PR31777
157 %union.U = type { i64 }
158
159 define void @foo(%union.U* nocapture %u) {
160 ; CHECK-LABEL: @foo(
161 ; CHECK-NEXT: entry:
162 ; CHECK-NEXT: [[I:%.*]] = getelementptr inbounds [[UNION_U:%.*]], %union.U* [[U:%.*]], i64 0, i32 0
163 ; CHECK-NEXT: store i64 11821949021847552, i64* [[I]], align 8
164 ; CHECK-NEXT: ret void
165 ;
166 entry:
167 %i = getelementptr inbounds %union.U, %union.U* %u, i64 0, i32 0
168 store i64 0, i64* %i, align 8
169 %s = bitcast %union.U* %u to i16*
170 store i16 42, i16* %s, align 8
171 ret void
172 }
0 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
1 ; RUN: opt -dse -enable-dse-partial-store-merging -S < %s | FileCheck %s
2 target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-f128:128:128-n8:16:32:64"
3
4 define void @byte_by_byte_replacement(i32 *%ptr) {
5 ; CHECK-LABEL: @byte_by_byte_replacement(
6 ; CHECK-NEXT: entry:
7 ; CHECK-NEXT: store i32 202050057, i32* [[PTR:%.*]]
8 ; CHECK-NEXT: ret void
9 ;
10 entry:
11 ;; This store's value should be modified as it should be better to use one
12 ;; larger store than several smaller ones.
13 ;; store will turn into 0x0C0B0A09 == 202050057
14 store i32 305419896, i32* %ptr ; 0x12345678
15 %bptr = bitcast i32* %ptr to i8*
16 %bptr1 = getelementptr inbounds i8, i8* %bptr, i64 1
17 %bptr2 = getelementptr inbounds i8, i8* %bptr, i64 2
18 %bptr3 = getelementptr inbounds i8, i8* %bptr, i64 3
19
20 ;; We should be able to merge these four stores with the i32 above
21 ; value (and bytes) stored before ; 0x12345678
22 store i8 9, i8* %bptr ; 09
23 store i8 10, i8* %bptr1 ; 0A
24 store i8 11, i8* %bptr2 ; 0B
25 store i8 12, i8* %bptr3 ; 0C
26 ; 0x0C0B0A09
27 ret void
28 }
29
30 define void @word_replacement(i64 *%ptr) {
31 ; CHECK-LABEL: @word_replacement(
32 ; CHECK-NEXT: entry:
33 ; CHECK-NEXT: store i64 8106482645252179720, i64* [[PTR:%.*]]
34 ; CHECK-NEXT: ret void
35 ;
36 entry:
37 store i64 72623859790382856, i64* %ptr ; 0x0102030405060708
38
39 %wptr = bitcast i64* %ptr to i16*
40 %wptr1 = getelementptr inbounds i16, i16* %wptr, i64 1
41 %wptr2 = getelementptr inbounds i16, i16* %wptr, i64 2
42 %wptr3 = getelementptr inbounds i16, i16* %wptr, i64 3
43
44 ;; We should be able to merge these two stores with the i64 one above
45 ; value (not bytes) stored before ; 0x0102030405060708
46 store i16 4128, i16* %wptr1 ; 1020
47 store i16 28800, i16* %wptr3 ; 7080
48 ; 0x7080030410200708
49 ret void
50 }
51
52
53 define void @differently_sized_replacements(i64 *%ptr) {
54 ; CHECK-LABEL: @differently_sized_replacements(
55 ; CHECK-NEXT: entry:
56 ; CHECK-NEXT: store i64 578437695752307201, i64* [[PTR:%.*]]
57 ; CHECK-NEXT: ret void
58 ;
59 entry:
60 store i64 579005069656919567, i64* %ptr ; 0x08090a0b0c0d0e0f
61
62 %bptr = bitcast i64* %ptr to i8*
63 %bptr6 = getelementptr inbounds i8, i8* %bptr, i64 6
64 %wptr = bitcast i64* %ptr to i16*
65 %wptr2 = getelementptr inbounds i16, i16* %wptr, i64 2
66 %dptr = bitcast i64* %ptr to i32*
67
68 ;; We should be able to merge all these stores with the i64 one above
69 ; value (not bytes) stored before ; 0x08090a0b0c0d0e0f
70 store i8 7, i8* %bptr6 ; 07
71 store i16 1541, i16* %wptr2 ; 0605
72 store i32 67305985, i32* %dptr ; 04030201
73 ; 0x0807060504030201
74 ret void
75 }
76
77
78 define void @multiple_replacements_to_same_byte(i64 *%ptr) {
79 ; CHECK-LABEL: @multiple_replacements_to_same_byte(
80 ; CHECK-NEXT: entry:
81 ; CHECK-NEXT: store i64 579005069522043393, i64* [[PTR:%.*]]
82 ; CHECK-NEXT: ret void
83 ;
84 entry:
85 store i64 579005069656919567, i64* %ptr ; 0x08090a0b0c0d0e0f
86
87 %bptr = bitcast i64* %ptr to i8*
88 %bptr3 = getelementptr inbounds i8, i8* %bptr, i64 3
89 %wptr = bitcast i64* %ptr to i16*
90 %wptr1 = getelementptr inbounds i16, i16* %wptr, i64 1
91 %dptr = bitcast i64* %ptr to i32*
92
93 ;; We should be able to merge all these stores with the i64 one above
94 ; value (not bytes) stored before ; 0x08090a0b0c0d0e0f
95 store i8 7, i8* %bptr3 ; 07
96 store i16 1541, i16* %wptr1 ; 0605
97 store i32 67305985, i32* %dptr ; 04030201
98 ; 0x08090a0b04030201
99 ret void
100 }
101
102 define void @merged_merges(i64 *%ptr) {
103 ; CHECK-LABEL: @merged_merges(
104 ; CHECK-NEXT: entry:
105 ; CHECK-NEXT: store i64 579005069572506113, i64* [[PTR:%.*]]
106 ; CHECK-NEXT: ret void
107 ;
108 entry:
109 store i64 579005069656919567, i64* %ptr ; 0x08090a0b0c0d0e0f
110
111 %bptr = bitcast i64* %ptr to i8*
112 %bptr3 = getelementptr inbounds i8, i8* %bptr, i64 3
113 %wptr = bitcast i64* %ptr to i16*
114 %wptr1 = getelementptr inbounds i16, i16* %wptr, i64 1
115 %dptr = bitcast i64* %ptr to i32*
116
117 ;; We should be able to merge all these stores with the i64 one above
118 ; value (not bytes) stored before ; 0x08090a0b0c0d0e0f
119 store i32 67305985, i32* %dptr ; 04030201
120 store i16 1541, i16* %wptr1 ; 0605
121 store i8 7, i8* %bptr3 ; 07
122 ; 0x08090a0b07050201
123 ret void
124 }
125
126 define signext i8 @shouldnt_merge_since_theres_a_full_overlap(i64 *%ptr) {
127 ; CHECK-LABEL: @shouldnt_merge_since_theres_a_full_overlap(
128 ; CHECK-NEXT: entry:
129 ; CHECK-NEXT: [[BPTR:%.*]] = bitcast i64* [[PTR:%.*]] to i8*
130 ; CHECK-NEXT: [[BPTRM1:%.*]] = getelementptr inbounds i8, i8* [[BPTR]], i64 -1
131 ; CHECK-NEXT: [[BPTR3:%.*]] = getelementptr inbounds i8, i8* [[BPTR]], i64 3
132 ; CHECK-NEXT: [[DPTR:%.*]] = bitcast i8* [[BPTRM1]] to i32*
133 ; CHECK-NEXT: [[QPTR:%.*]] = bitcast i8* [[BPTR3]] to i64*
134 ; CHECK-NEXT: store i32 1234, i32* [[DPTR]], align 1
135 ; CHECK-NEXT: store i64 5678, i64* [[QPTR]], align 1
136 ; CHECK-NEXT: ret i8 0
137 ;
138 entry:
139
140 ; Also check that alias.scope metadata doesn't get dropped
141 store i64 0, i64* %ptr, !alias.scope !32
142
143 %bptr = bitcast i64* %ptr to i8*
144 %bptrm1 = getelementptr inbounds i8, i8* %bptr, i64 -1
145 %bptr3 = getelementptr inbounds i8, i8* %bptr, i64 3
146 %dptr = bitcast i8* %bptrm1 to i32*
147 %qptr = bitcast i8* %bptr3 to i64*
148
149 store i32 1234, i32* %dptr, align 1
150 store i64 5678, i64* %qptr, align 1
151
152 ret i8 0
153 }
154
155 ;; Test case from PR31777
156 %union.U = type { i64 }
157
158 define void @foo(%union.U* nocapture %u) {
159 ; CHECK-LABEL: @foo(
160 ; CHECK-NEXT: entry:
161 ; CHECK-NEXT: [[I:%.*]] = getelementptr inbounds [[UNION_U:%.*]], %union.U* [[U:%.*]], i64 0, i32 0
162 ; CHECK-NEXT: store i64 42, i64* [[I]], align 8
163 ; CHECK-NEXT: ret void
164 ;
165 entry:
166 %i = getelementptr inbounds %union.U, %union.U* %u, i64 0, i32 0
167 store i64 0, i64* %i, align 8, !dbg !22, !tbaa !26, !noalias !30, !nontemporal !29
168 %s = bitcast %union.U* %u to i16*
169 store i16 42, i16* %s, align 8
170 ret void
171 }
172
173 !0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus, file: !1, producer: "clang version 5.0.0 (trunk 306512)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
174 !1 = !DIFile(filename: "me.cpp", directory: "/compiler-explorer")
175 !2 = !{}
176 !7 = distinct !DISubprogram(name: "foo", linkageName: "foo(U*)", scope: !1, file: !1, line: 9, type: !8, isLocal: false, isDefinition: true, scopeLine: 9, flags: DIFlagPrototyped, isOptimized: true, unit: !0, variables: !20)
177 !8 = !DISubroutineType(types: !9)
178 !9 = !{null, !10}
179 !10 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !11, size: 64)
180 !11 = distinct !DICompositeType(tag: DW_TAG_union_type, name: "U", file: !1, line: 4, size: 64, elements: !12, identifier: "typeinfo name for U")
181 !12 = !{!13, !17}
182 !13 = !DIDerivedType(tag: DW_TAG_member, name: "i", scope: !11, file: !1, line: 5, baseType: !14, size: 64)
183 !14 = !DIDerivedType(tag: DW_TAG_typedef, name: "uint64_t", file: !15, line: 55, baseType: !16)
184 !15 = !DIFile(filename: "/usr/include/stdint.h", directory: "/compiler-explorer")
185 !16 = !DIBasicType(name: "long unsigned int", size: 64, encoding: DW_ATE_unsigned)
186 !17 = !DIDerivedType(tag: DW_TAG_member, name: "s", scope: !11, file: !1, line: 6, baseType: !18, size: 16)
187 !18 = !DIDerivedType(tag: DW_TAG_typedef, name: "uint16_t", file: !15, line: 49, baseType: !19)
188 !19 = !DIBasicType(name: "unsigned short", size: 16, encoding: DW_ATE_unsigned)
189 !20 = !{!21}
190 !21 = !DILocalVariable(name: "u", arg: 1, scope: !7, file: !1, line: 9, type: !10)
191 !22 = !DILocation(line: 10, column: 8, scope: !7)
192
193 !26 = !{!27, !27, i64 0}
194 !27 = !{!"omnipotent char", !28, i64 0}
195 !28 = !{!"Simple C++ TBAA"}
196
197 !29 = !{i32 1}
198
199 ; Domains and scopes which might alias
200 !30 = !{!30}
201 !31 = !{!31, !30}
202
203 !32 = !{!32}
204 !33 = !{!33, !32}