File: cxx1z-aligned-allocation.cpp

package info (click to toggle)
llvm-toolchain-15 1%3A15.0.6-4
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 1,554,644 kB
  • sloc: cpp: 5,922,452; ansic: 1,012,136; asm: 674,362; python: 191,568; objc: 73,855; f90: 42,327; lisp: 31,913; pascal: 11,973; javascript: 10,144; sh: 9,421; perl: 7,447; ml: 5,527; awk: 3,523; makefile: 2,520; xml: 885; cs: 573; fortran: 567
file content (222 lines) | stat: -rw-r--r-- 9,588 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
// Check that delete exprs call aligned (de)allocation functions if
// -faligned-allocation is passed in both C++11 and C++14.
// RUN: %clang_cc1 -no-opaque-pointers -std=c++11 -fexceptions -fsized-deallocation -faligned-allocation %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s
// RUN: %clang_cc1 -no-opaque-pointers -std=c++14 -fexceptions -fsized-deallocation -faligned-allocation %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s
// RUN: %clang_cc1 -no-opaque-pointers -std=c++1z -fexceptions -fsized-deallocation %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s

// RUN: %clang_cc1 -no-opaque-pointers -std=c++1z -fexceptions -fsized-deallocation %s -emit-llvm -triple x86_64-windows-msvc -o - | FileCheck %s --check-prefix=CHECK-MS

// Check that we don't used aligned (de)allocation without -faligned-allocation or C++1z.
// RUN: %clang_cc1 -no-opaque-pointers -std=c++14 -DUNALIGNED -fexceptions %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s --check-prefix=CHECK-UNALIGNED
// RUN: %clang_cc1 -no-opaque-pointers -std=c++1z -DUNALIGNED -fexceptions -fno-aligned-allocation %s -emit-llvm -triple x86_64-linux-gnu -o - | FileCheck %s --check-prefix=CHECK-UNALIGNED

// CHECK-UNALIGNED-NOT: _Znwm_St11align_val_t
// CHECK-UNALIGNED-NOT: _Znam_St11align_val_t
// CHECK-UNALIGNED-NOT: _ZdlPv_St11align_val_t
// CHECK-UNALIGNED-NOT: _ZdaPv_St11align_val_t
// CHECK-UNALIGNED-NOT: _ZdlPvm_St11align_val_t
// CHECK-UNALIGNED-NOT: _ZdaPvm_St11align_val_t

typedef decltype(sizeof(0)) size_t;
namespace std { enum class align_val_t : size_t {}; }

#define OVERALIGNED alignas(__STDCPP_DEFAULT_NEW_ALIGNMENT__ * 2)

// Global new and delete.
// ======================
struct OVERALIGNED A { A(); int n[128]; };

// CHECK-LABEL: define {{.*}} @_Z2a0v()
// CHECK: %[[ALLOC:.*]] = call noalias noundef nonnull align 32 i8* @_ZnwmSt11align_val_t(i64 noundef 512, i64 noundef 32)
// CHECK: call void @_ZdlPvSt11align_val_t(i8* noundef %[[ALLOC]], i64 noundef 32)
// CHECK-MS-LABEL: define {{.*}} @"?a0@@YAPEAXXZ"()
// CHECK-MS: %[[ALLOC:.*]] = call noalias noundef nonnull align 32 i8* @"??2@YAPEAX_KW4align_val_t@std@@@Z"(i64 noundef 512, i64 noundef 32)
// CHECK-MS: cleanuppad
// CHECK-MS: call void @"??3@YAXPEAXW4align_val_t@std@@@Z"(i8* noundef %[[ALLOC]], i64 noundef 32)
void *a0() { return new A; }

// FIXME: Why don't we call the sized array deallocation overload in this case?
// The size is known.
//
// CHECK-LABEL: define {{.*}} @_Z2a1l(
// CHECK: %[[ALLOC:.*]] = call noalias noundef nonnull align 32 i8* @_ZnamSt11align_val_t(i64 noundef %{{.*}}, i64 noundef 32)
// No array cookie.
// CHECK-NOT: store
// CHECK: invoke void @_ZN1AC1Ev(
// CHECK: call void @_ZdaPvSt11align_val_t(i8* noundef %[[ALLOC]], i64 noundef 32)
// CHECK-MS-LABEL: define {{.*}} @"?a1@@YAPEAXJ@Z"(
// CHECK-MS: %[[ALLOC:.*]] = call noalias noundef nonnull align 32 i8* @"??_U@YAPEAX_KW4align_val_t@std@@@Z"(i64 noundef %{{.*}}, i64 noundef 32)
// No array cookie.
// CHECK-MS-NOT: store
// CHECK-MS: invoke noundef %struct.A* @"??0A@@QEAA@XZ"(
// CHECK-MS: cleanuppad
// CHECK-MS: call void @"??_V@YAXPEAXW4align_val_t@std@@@Z"(i8* noundef %[[ALLOC]], i64 noundef 32)
void *a1(long n) { return new A[n]; }

// CHECK-LABEL: define {{.*}} @_Z2a2P1A(
// CHECK: call void @_ZdlPvmSt11align_val_t(i8* noundef %{{.*}}, i64 noundef 512, i64 noundef 32) #9
void a2(A *p) { delete p; }

// CHECK-LABEL: define {{.*}} @_Z2a3P1A(
// CHECK: call void @_ZdaPvSt11align_val_t(i8* noundef %{{.*}}, i64 noundef 32) #9
void a3(A *p) { delete[] p; }


// Class-specific usual new and delete.
// ====================================
struct OVERALIGNED B {
  B();
  // These are just a distraction. We should ignore them.
  void *operator new(size_t);
  void operator delete(void*, size_t);
  void operator delete[](void*, size_t);

  void *operator new(size_t, std::align_val_t);
  void operator delete(void*, std::align_val_t);
  void operator delete[](void*, std::align_val_t);

  int n[128];
};

// CHECK-LABEL: define {{.*}} @_Z2b0v()
// CHECK: %[[ALLOC:.*]] = call noundef i8* @_ZN1BnwEmSt11align_val_t(i64 noundef 512, i64 noundef 32)
// CHECK: call void @_ZN1BdlEPvSt11align_val_t(i8* noundef %[[ALLOC]], i64 noundef 32)
void *b0() { return new B; }

// CHECK-LABEL: define {{.*}} @_Z2b1l(
// CHECK: %[[ALLOC:.*]] = call noalias noundef nonnull align 32 i8* @_ZnamSt11align_val_t(i64 noundef %{{.*}}, i64 noundef 32)
// No array cookie.
// CHECK-NOT: store
// CHECK: invoke void @_ZN1BC1Ev(
// CHECK: call void @_ZN1BdaEPvSt11align_val_t(i8* noundef %[[ALLOC]], i64 noundef 32)
void *b1(long n) { return new B[n]; }

// CHECK-LABEL: define {{.*}} @_Z2b2P1B(
// CHECK: call void @_ZN1BdlEPvSt11align_val_t(i8* noundef %{{.*}}, i64 noundef 32)
void b2(B *p) { delete p; }

// CHECK-LABEL: define {{.*}} @_Z2b3P1B(
// CHECK: call void @_ZN1BdaEPvSt11align_val_t(i8* noundef %{{.*}}, i64 noundef 32)
void b3(B *p) { delete[] p; }

struct OVERALIGNED C {
  C();
  void *operator new[](size_t, std::align_val_t);
  void operator delete[](void*, size_t, std::align_val_t);

  // It doesn't matter that we have an unaligned operator delete[] that doesn't
  // want the size. What matters is that the aligned one does.
  void operator delete[](void*);
};

// This one has an array cookie.
// CHECK-LABEL: define {{.*}} @_Z2b4l(
// CHECK: call {{.*}} @llvm.umul.with.overflow{{.*}}i64 32
// CHECK: call {{.*}} @llvm.uadd.with.overflow{{.*}}i64 32
// CHECK: %[[ALLOC:.*]] = call noundef i8* @_ZN1CnaEmSt11align_val_t(i64 noundef %{{.*}}, i64 noundef 32)
// CHECK: store
// CHECK: call void @_ZN1CC1Ev(
//
// Note, we're still calling a placement allocation function, and there is no
// matching placement operator delete. =(
// FIXME: This seems broken.
// CHECK-NOT: call void @_ZN1CdaEPvmSt11align_val_t(
#ifndef UNALIGNED
void *b4(long n) { return new C[n]; }
#endif

// CHECK-LABEL: define {{.*}} @_Z2b5P1C(
// CHECK: mul i64{{.*}} 32
// CHECK: add i64{{.*}} 32
// CHECK: call void @_ZN1CdaEPvmSt11align_val_t(
void b5(C *p) { delete[] p; }


// Global placement new.
// =====================

struct Q { int n; } q;
void *operator new(size_t, Q);
void *operator new(size_t, std::align_val_t, Q);
void operator delete(void*, Q);
void operator delete(void*, std::align_val_t, Q);

// CHECK-LABEL: define {{.*}} @_Z2c0v(
// CHECK: %[[ALLOC:.*]] = call noundef i8* @_ZnwmSt11align_val_t1Q(i64 noundef 512, i64 noundef 32, i32 %
// CHECK: call void @_ZdlPvSt11align_val_t1Q(i8* noundef %[[ALLOC]], i64 noundef 32, i32 %
void *c0() { return new (q) A; }


// Class-specific placement new.
// =============================

struct OVERALIGNED D {
  D();
  void *operator new(size_t, Q);
  void *operator new(size_t, std::align_val_t, Q);
  void operator delete(void*, Q);
  void operator delete(void*, std::align_val_t, Q);
};

// CHECK-LABEL: define {{.*}} @_Z2d0v(
// CHECK: %[[ALLOC:.*]] = call noundef i8* @_ZN1DnwEmSt11align_val_t1Q(i64 noundef 32, i64 noundef 32, i32 %
// CHECK: call void @_ZN1DdlEPvSt11align_val_t1Q(i8* noundef %[[ALLOC]], i64 noundef 32, i32 %
void *d0() { return new (q) D; }


// Calling aligned new with placement syntax.
// ==========================================

#ifndef UNALIGNED
// CHECK-LABEL: define {{.*}} @_Z2e0v(
// CHECK: %[[ALLOC:.*]] = call noalias noundef nonnull align 4 i8* @_ZnwmSt11align_val_t(i64 noundef 512, i64 noundef 4)
// CHECK: call void @_ZdlPvSt11align_val_t(i8* noundef %[[ALLOC]], i64 noundef 4)
void *e0() { return new (std::align_val_t(4)) A; }

// CHECK-LABEL: define {{.*}} @_Z2e1v(
// CHECK: %[[ALLOC:.*]] = call noundef i8* @_ZN1BnwEmSt11align_val_t(i64 noundef 512, i64 noundef 4)
// CHECK: call void @_ZN1BdlEPvSt11align_val_t(i8* noundef %[[ALLOC]], i64 noundef 4)
void *e1() { return new (std::align_val_t(4)) B; }
#endif

// Variadic placement/non-placement allocation functions.
// ======================================================

struct OVERALIGNED F {
  F();
  void *operator new(size_t, ...);
  void operator delete(void*, ...);
  int n[128];
};

// CHECK-LABEL: define {{.*}} @_Z2f0v(
// CHECK: %[[ALLOC:.*]] = call noundef i8* (i64, ...) @_ZN1FnwEmz(i64 noundef 512, i64 noundef 32)
// Non-placement allocation function, uses normal deallocation lookup which
// cares about whether a parameter has type std::align_val_t.
// CHECK: call void (i8*, ...) @_ZN1FdlEPvz(i8* noundef %[[ALLOC]])
void *f0() { return new F; }

// CHECK-LABEL: define {{.*}} @_Z2f1v(
// CHECK: %[[ALLOC:.*]] = call noundef i8* (i64, ...) @_ZN1FnwEmz(i64 noundef 512, i64 noundef 32, i32 %
// Placement allocation function, uses placement deallocation matching, which
// passes same arguments and therefore includes alignment.
// CHECK: call void (i8*, ...) @_ZN1FdlEPvz(i8* noundef %[[ALLOC]], i64 noundef 32, i32 %
void *f1() { return new (q) F; }

struct OVERALIGNED G {
  G();
  void *operator new(size_t, std::align_val_t, ...);
  void operator delete(void*, std::align_val_t, ...);
  int n[128];
};
#ifndef UNALIGNED
// CHECK-LABEL: define {{.*}} @_Z2g0v
// CHECK: %[[ALLOC:.*]] = call noundef i8* (i64, i64, ...) @_ZN1GnwEmSt11align_val_tz(i64 noundef 512, i64 noundef 32)
// CHECK: call void (i8*, i64, ...) @_ZN1GdlEPvSt11align_val_tz(i8* noundef %[[ALLOC]], i64 noundef 32)
void *g0() { return new G; }

// CHECK-LABEL: define {{.*}} @_Z2g1v
// CHECK: %[[ALLOC:.*]] = call noundef i8* (i64, i64, ...) @_ZN1GnwEmSt11align_val_tz(i64 noundef 512, i64 noundef 32, i32 %
// CHECK: call void (i8*, i64, ...) @_ZN1GdlEPvSt11align_val_tz(i8* noundef %[[ALLOC]], i64 noundef 32, i32 %
void *g1() { return new (q) G; }
#endif