xref: /llvm-project/clang/test/CodeGenCXX/matrix-type.cpp (revision 12f78e740c5419f7d1fbcf8f2106e7a40cd1d6f7)
1 // RUN: %clang_cc1 -Wno-error=return-type -no-enable-noundef-analysis -fenable-matrix -fclang-abi-compat=latest -triple x86_64-apple-darwin %s -emit-llvm -disable-llvm-passes -o - -std=c++17 | FileCheck %s
2 
3 typedef double dx5x5_t __attribute__((matrix_type(5, 5)));
4 typedef float fx3x4_t __attribute__((matrix_type(3, 4)));
5 
6 // CHECK: %struct.Matrix = type { i8, [12 x float], float }
7 
8 void load_store(dx5x5_t *a, dx5x5_t *b) {
9   // CHECK-LABEL:  define{{.*}} void @_Z10load_storePu11matrix_typeILm5ELm5EdES0_(
10   // CHECK-NEXT:  entry:
11   // CHECK-NEXT:    %a.addr = alloca ptr, align 8
12   // CHECK-NEXT:    %b.addr = alloca ptr, align 8
13   // CHECK-NEXT:    store ptr %a, ptr %a.addr, align 8
14   // CHECK-NEXT:    store ptr %b, ptr %b.addr, align 8
15   // CHECK-NEXT:    %0 = load ptr, ptr %b.addr, align 8
16   // CHECK-NEXT:    %1 = load <25 x double>, ptr %0, align 8
17   // CHECK-NEXT:    %2 = load ptr, ptr %a.addr, align 8
18   // CHECK-NEXT:    store <25 x double> %1, ptr %2, align 8
19   // CHECK-NEXT:   ret void
20 
21   *a = *b;
22 }
23 
24 typedef float fx3x3_t __attribute__((matrix_type(3, 3)));
25 
26 void parameter_passing(fx3x3_t a, fx3x3_t *b) {
27   // CHECK-LABEL: define{{.*}} void @_Z17parameter_passingu11matrix_typeILm3ELm3EfEPS_(
28   // CHECK-NEXT:  entry:
29   // CHECK-NEXT:    %a.addr = alloca [9 x float], align 4
30   // CHECK-NEXT:    %b.addr = alloca ptr, align 8
31   // CHECK-NEXT:    store <9 x float> %a, ptr %a.addr, align 4
32   // CHECK-NEXT:    store ptr %b, ptr %b.addr, align 8
33   // CHECK-NEXT:    %0 = load <9 x float>, ptr %a.addr, align 4
34   // CHECK-NEXT:    %1 = load ptr, ptr %b.addr, align 8
35   // CHECK-NEXT:    store <9 x float> %0, ptr %1, align 4
36   // CHECK-NEXT:    ret void
37   *b = a;
38 }
39 
40 fx3x3_t return_matrix(fx3x3_t *a) {
41   // CHECK-LABEL: define{{.*}} <9 x float> @_Z13return_matrixPu11matrix_typeILm3ELm3EfE(
42   // CHECK-NEXT:  entry:
43   // CHECK-NEXT:    %a.addr = alloca ptr, align 8
44   // CHECK-NEXT:    store ptr %a, ptr %a.addr, align 8
45   // CHECK-NEXT:    %0 = load ptr, ptr %a.addr, align 8
46   // CHECK-NEXT:    %1 = load <9 x float>, ptr %0, align 4
47   // CHECK-NEXT:    ret <9 x float> %1
48   return *a;
49 }
50 
51 struct Matrix {
52   char Tmp1;
53   fx3x4_t Data;
54   float Tmp2;
55 };
56 
57 void matrix_struct_pointers(Matrix *a, Matrix *b) {
58   // CHECK-LABEL: define{{.*}} void @_Z22matrix_struct_pointersP6MatrixS0_(
59   // CHECK-NEXT:  entry:
60   // CHECK-NEXT:    %a.addr = alloca ptr, align 8
61   // CHECK-NEXT:    %b.addr = alloca ptr, align 8
62   // CHECK-NEXT:    store ptr %a, ptr %a.addr, align 8
63   // CHECK-NEXT:    store ptr %b, ptr %b.addr, align 8
64   // CHECK-NEXT:    %0 = load ptr, ptr %a.addr, align 8
65   // CHECK-NEXT:    %Data = getelementptr inbounds nuw %struct.Matrix, ptr %0, i32 0, i32 1
66   // CHECK-NEXT:    %1 = load <12 x float>, ptr %Data, align 4
67   // CHECK-NEXT:    %2 = load ptr, ptr %b.addr, align 8
68   // CHECK-NEXT:    %Data1 = getelementptr inbounds nuw %struct.Matrix, ptr %2, i32 0, i32 1
69   // CHECK-NEXT:    store <12 x float> %1, ptr %Data1, align 4
70   // CHECK-NEXT:    ret void
71   b->Data = a->Data;
72 }
73 
74 void matrix_struct_reference(Matrix &a, Matrix &b) {
75   // CHECK-LABEL: define{{.*}} void @_Z23matrix_struct_referenceR6MatrixS0_(
76   // CHECK-NEXT:  entry:
77   // CHECK-NEXT:    %a.addr = alloca ptr, align 8
78   // CHECK-NEXT:    %b.addr = alloca ptr, align 8
79   // CHECK-NEXT:    store ptr %a, ptr %a.addr, align 8
80   // CHECK-NEXT:    store ptr %b, ptr %b.addr, align 8
81   // CHECK-NEXT:    %0 = load ptr, ptr %a.addr, align 8
82   // CHECK-NEXT:    %Data = getelementptr inbounds nuw %struct.Matrix, ptr %0, i32 0, i32 1
83   // CHECK-NEXT:    %1 = load <12 x float>, ptr %Data, align 4
84   // CHECK-NEXT:    %2 = load ptr, ptr %b.addr, align 8
85   // CHECK-NEXT:    %Data1 = getelementptr inbounds nuw %struct.Matrix, ptr %2, i32 0, i32 1
86   // CHECK-NEXT:    store <12 x float> %1, ptr %Data1, align 4
87   // CHECK-NEXT:    ret void
88   b.Data = a.Data;
89 }
90 
91 class MatrixClass {
92 public:
93   int Tmp1;
94   fx3x4_t Data;
95   long Tmp2;
96 };
97 
98 void matrix_class_reference(MatrixClass &a, MatrixClass &b) {
99   // CHECK-LABEL: define{{.*}} void @_Z22matrix_class_referenceR11MatrixClassS0_(
100   // CHECK-NEXT:  entry:
101   // CHECK-NEXT:    %a.addr = alloca ptr, align 8
102   // CHECK-NEXT:    %b.addr = alloca ptr, align 8
103   // CHECK-NEXT:    store ptr %a, ptr %a.addr, align 8
104   // CHECK-NEXT:    store ptr %b, ptr %b.addr, align 8
105   // CHECK-NEXT:    %0 = load ptr, ptr %a.addr, align 8
106   // CHECK-NEXT:    %Data = getelementptr inbounds nuw %class.MatrixClass, ptr %0, i32 0, i32 1
107   // CHECK-NEXT:    %1 = load <12 x float>, ptr %Data, align 4
108   // CHECK-NEXT:    %2 = load ptr, ptr %b.addr, align 8
109   // CHECK-NEXT:    %Data1 = getelementptr inbounds nuw %class.MatrixClass, ptr %2, i32 0, i32 1
110   // CHECK-NEXT:    store <12 x float> %1, ptr %Data1, align 4
111   // CHECK-NEXT:    ret void
112   b.Data = a.Data;
113 }
114 
115 template <typename Ty, unsigned Rows, unsigned Cols>
116 class MatrixClassTemplate {
117 public:
118   using MatrixTy = Ty __attribute__((matrix_type(Rows, Cols)));
119   int Tmp1;
120   MatrixTy Data;
121   long Tmp2;
122 };
123 
124 template <typename Ty, unsigned Rows, unsigned Cols>
125 void matrix_template_reference(MatrixClassTemplate<Ty, Rows, Cols> &a, MatrixClassTemplate<Ty, Rows, Cols> &b) {
126   b.Data = a.Data;
127 }
128 
129 MatrixClassTemplate<float, 10, 15> matrix_template_reference_caller(float *Data) {
130   // CHECK-LABEL: define{{.*}} void @_Z32matrix_template_reference_callerPf(ptr dead_on_unwind noalias writable sret(%class.MatrixClassTemplate) align 8 %agg.result, ptr %Data
131   // CHECK-NEXT:  entry:
132   // CHECK-NEXT:    %Data.addr = alloca ptr, align 8
133   // CHECK-NEXT:    %Arg = alloca %class.MatrixClassTemplate, align 8
134   // CHECK-NEXT:    store ptr %Data, ptr %Data.addr, align 8
135   // CHECK-NEXT:    %0 = load ptr, ptr %Data.addr, align 8
136   // CHECK-NEXT:    %1 = load <150 x float>, ptr %0, align 4
137   // CHECK-NEXT:    %Data1 = getelementptr inbounds nuw %class.MatrixClassTemplate, ptr %Arg, i32 0, i32 1
138   // CHECK-NEXT:    store <150 x float> %1, ptr %Data1, align 4
139   // CHECK-NEXT:    call void @_Z25matrix_template_referenceIfLj10ELj15EEvR19MatrixClassTemplateIT_XT0_EXT1_EES3_(ptr nonnull align 8 dereferenceable(616) %Arg, ptr nonnull align 8 dereferenceable(616) %agg.result)
140   // CHECK-NEXT:    ret void
141 
142   // CHECK-LABEL: define linkonce_odr void @_Z25matrix_template_referenceIfLj10ELj15EEvR19MatrixClassTemplateIT_XT0_EXT1_EES3_(ptr nonnull align 8 dereferenceable(616) %a, ptr nonnull align 8 dereferenceable(616) %b)
143   // CHECK-NEXT:  entry:
144   // CHECK-NEXT:    %a.addr = alloca ptr, align 8
145   // CHECK-NEXT:    %b.addr = alloca ptr, align 8
146   // CHECK-NEXT:    store ptr %a, ptr %a.addr, align 8
147   // CHECK-NEXT:    store ptr %b, ptr %b.addr, align 8
148   // CHECK-NEXT:    %0 = load ptr, ptr %a.addr, align 8
149   // CHECK-NEXT:    %Data = getelementptr inbounds nuw %class.MatrixClassTemplate, ptr %0, i32 0, i32 1
150   // CHECK-NEXT:    %1 = load <150 x float>, ptr %Data, align 4
151   // CHECK-NEXT:    %2 = load ptr, ptr %b.addr, align 8
152   // CHECK-NEXT:    %Data1 = getelementptr inbounds nuw %class.MatrixClassTemplate, ptr %2, i32 0, i32 1
153   // CHECK-NEXT:    store <150 x float> %1, ptr %Data1, align 4
154   // CHECK-NEXT:    ret void
155 
156   MatrixClassTemplate<float, 10, 15> Result, Arg;
157   Arg.Data = *((MatrixClassTemplate<float, 10, 15>::MatrixTy *)Data);
158   matrix_template_reference(Arg, Result);
159   return Result;
160 }
161 
162 template <class T, unsigned long R, unsigned long C>
163 using matrix = T __attribute__((matrix_type(R, C)));
164 
165 template <int N>
166 struct selector {};
167 
168 template <class T, unsigned long R, unsigned long C>
169 selector<0> use_matrix(matrix<T, R, C> &m) {}
170 
171 template <class T, unsigned long R>
172 selector<1> use_matrix(matrix<T, R, 10> &m) {}
173 
174 template <class T>
175 selector<2> use_matrix(matrix<T, 10, 10> &m) {}
176 
177 template <class T, unsigned long C>
178 selector<3> use_matrix(matrix<T, 10, C> &m) {}
179 
180 template <unsigned long R, unsigned long C>
181 selector<4> use_matrix(matrix<float, R, C> &m) {}
182 
183 void test_template_deduction() {
184 
185   // CHECK-LABEL: define{{.*}} void @_Z23test_template_deductionv()
186   // CHECK-NEXT:  entry:
187   // CHECK-NEXT:    %m0 = alloca [120 x i32], align 4
188   // CHECK-NEXT:    %w = alloca %struct.selector, align 1
189   // CHECK-NEXT:    %undef.agg.tmp = alloca %struct.selector, align 1
190   // CHECK-NEXT:    %m1 = alloca [100 x i32], align 4
191   // CHECK-NEXT:    %x = alloca %struct.selector.0, align 1
192   // CHECK-NEXT:    %undef.agg.tmp1 = alloca %struct.selector.0, align 1
193   // CHECK-NEXT:    %m2 = alloca [120 x i32], align 4
194   // CHECK-NEXT:    %y = alloca %struct.selector.1, align 1
195   // CHECK-NEXT:    %undef.agg.tmp2 = alloca %struct.selector.1, align 1
196   // CHECK-NEXT:    %m3 = alloca [144 x i32], align 4
197   // CHECK-NEXT:    %z = alloca %struct.selector.2, align 1
198   // CHECK-NEXT:    %undef.agg.tmp3 = alloca %struct.selector.2, align 1
199   // CHECK-NEXT:    %m4 = alloca [144 x float], align 4
200   // CHECK-NEXT:    %v = alloca %struct.selector.3, align 1
201   // CHECK-NEXT:    %undef.agg.tmp4 = alloca %struct.selector.3, align 1
202   // CHECK-NEXT:    call void @_Z10use_matrixIiLm12EE8selectorILi3EERu11matrix_typeILm10EXT0_ET_E(ptr nonnull align 4 dereferenceable(480) %m0)
203   // CHECK-NEXT:    call void @_Z10use_matrixIiE8selectorILi2EERu11matrix_typeILm10ELm10ET_E(ptr nonnull align 4 dereferenceable(400) %m1)
204   // CHECK-NEXT:    call void @_Z10use_matrixIiLm12EE8selectorILi1EERu11matrix_typeIXT0_ELm10ET_E(ptr nonnull align 4 dereferenceable(480) %m2)
205   // CHECK-NEXT:    call void @_Z10use_matrixIiLm12ELm12EE8selectorILi0EERu11matrix_typeIXT0_EXT1_ET_E(ptr nonnull align 4 dereferenceable(576) %m3)
206   // CHECK-NEXT:    call void @_Z10use_matrixILm12ELm12EE8selectorILi4EERu11matrix_typeIXT_EXT0_EfE(ptr nonnull align 4 dereferenceable(576) %m4)
207   // CHECK-NEXT:    ret void
208 
209   // CHECK-LABEL: define linkonce_odr void @_Z10use_matrixIiLm12EE8selectorILi3EERu11matrix_typeILm10EXT0_ET_E(ptr nonnull align 4 dereferenceable(480) %m)
210   // CHECK-NEXT:  entry:
211   // CHECK-NEXT:    %m.addr = alloca ptr, align 8
212   // CHECK-NEXT:    store ptr %m, ptr %m.addr, align 8
213   // CHECK-NEXT:    call void @llvm.trap()
214   // CHECK-NEXT:    unreachable
215 
216   // CHECK-LABEL: define linkonce_odr void @_Z10use_matrixIiE8selectorILi2EERu11matrix_typeILm10ELm10ET_E(ptr nonnull align 4 dereferenceable(400) %m)
217   // CHECK-NEXT:  entry:
218   // CHECK-NEXT:    %m.addr = alloca ptr, align 8
219   // CHECK-NEXT:    store ptr %m, ptr %m.addr, align 8
220   // CHECK-NEXT:    call void @llvm.trap()
221   // CHECK-NEXT:    unreachable
222 
223   // CHECK-LABEL: define linkonce_odr void @_Z10use_matrixIiLm12EE8selectorILi1EERu11matrix_typeIXT0_ELm10ET_E(ptr nonnull align 4 dereferenceable(480) %m)
224   // CHECK-NEXT:  entry:
225   // CHECK-NEXT:    %m.addr = alloca ptr, align 8
226   // CHECK-NEXT:    store ptr %m, ptr %m.addr, align 8
227   // CHECK-NEXT:    call void @llvm.trap()
228   // CHECK-NEXT:    unreachable
229 
230   // CHECK-LABEL: define linkonce_odr void @_Z10use_matrixIiLm12ELm12EE8selectorILi0EERu11matrix_typeIXT0_EXT1_ET_E(ptr nonnull align 4 dereferenceable(576) %m)
231   // CHECK-NEXT:  entry:
232   // CHECK-NEXT:    %m.addr = alloca ptr, align 8
233   // CHECK-NEXT:    store ptr %m, ptr %m.addr, align 8
234   // CHECK-NEXT:    call void @llvm.trap()
235   // CHECK-NEXT:    unreachable
236 
237   // CHECK-LABEL: define linkonce_odr void @_Z10use_matrixILm12ELm12EE8selectorILi4EERu11matrix_typeIXT_EXT0_EfE(ptr nonnull align 4 dereferenceable(576)
238   // CHECK-NEXT:  entry:
239   // CHECK-NEXT:    %m.addr = alloca ptr, align 8
240   // CHECK-NEXT:    store ptr %m, ptr %m.addr, align 8
241   // CHECK-NEXT:    call void @llvm.trap()
242   // CHECK-NEXT:    unreachable
243 
244   matrix<int, 10, 12> m0;
245   selector<3> w = use_matrix(m0);
246   matrix<int, 10, 10> m1;
247   selector<2> x = use_matrix(m1);
248   matrix<int, 12, 10> m2;
249   selector<1> y = use_matrix(m2);
250   matrix<int, 12, 12> m3;
251   selector<0> z = use_matrix(m3);
252   matrix<float, 12, 12> m4;
253   selector<4> v = use_matrix(m4);
254 }
255 
256 template <auto R>
257 void foo(matrix<int, R, 10> &m) {
258 }
259 
260 void test_auto_t() {
261   // CHECK-LABEL: define{{.*}} void @_Z11test_auto_tv()
262   // CHECK-NEXT:  entry:
263   // CHECK-NEXT:    %m = alloca [130 x i32], align 4
264   // CHECK-NEXT:    call void @_Z3fooITnDaLm13EEvRu11matrix_typeIXT_ELm10EiE(ptr nonnull align 4 dereferenceable(520) %m)
265   // CHECK-NEXT:    ret void
266 
267   // CHECK-LABEL: define linkonce_odr void @_Z3fooITnDaLm13EEvRu11matrix_typeIXT_ELm10EiE(ptr nonnull align 4 dereferenceable(520) %m)
268   // CHECK-NEXT:  entry:
269   // CHECK-NEXT:    %m.addr = alloca ptr, align 8
270   // CHECK-NEXT:    store ptr %m, ptr %m.addr, align 8
271   // CHECK-NEXT:    ret void
272 
273   matrix<int, 13, 10> m;
274   foo(m);
275 }
276 
277 template <unsigned long R, unsigned long C>
278 matrix<float, R + 1, C + 2> use_matrix_2(matrix<int, R, C> &m) {}
279 
280 template <unsigned long R, unsigned long C>
281 selector<0> use_matrix_2(matrix<int, R + 2, C / 2> &m1, matrix<float, R, C> &m2) {}
282 
283 template <unsigned long R, unsigned long C>
284 selector<1> use_matrix_2(matrix<int, R + C, C> &m1, matrix<float, R, C - R> &m2) {}
285 
286 template <unsigned long R>
287 matrix<float, R + R, R - 3> use_matrix_2(matrix<int, R, 10> &m1) {}
288 
289 template <unsigned long R>
290 selector<2> use_matrix_3(matrix<int, R - 2, R> &m) {}
291 
292 void test_use_matrix_2() {
293   // CHECK-LABEL: define{{.*}} void @_Z17test_use_matrix_2v()
294   // CHECK-NEXT:  entry:
295   // CHECK-NEXT:    %m1 = alloca [24 x i32], align 4
296   // CHECK-NEXT:    %r1 = alloca [40 x float], align 4
297   // CHECK-NEXT:    %m2 = alloca [24 x float], align 4
298   // CHECK-NEXT:    %r2 = alloca %struct.selector.2, align 1
299   // CHECK-NEXT:    %undef.agg.tmp = alloca %struct.selector.2, align 1
300   // CHECK-NEXT:    %m3 = alloca [104 x i32], align 4
301   // CHECK-NEXT:    %m4 = alloca [15 x float], align 4
302   // CHECK-NEXT:    %r3 = alloca %struct.selector.1, align 1
303   // CHECK-NEXT:    %undef.agg.tmp1 = alloca %struct.selector.1, align 1
304   // CHECK-NEXT:    %m5 = alloca [50 x i32], align 4
305   // CHECK-NEXT:    %r4 = alloca [20 x float], align 4
306   // CHECK-NEXT:    %r5 = alloca %struct.selector.0, align 1
307   // CHECK-NEXT:    %undef.agg.tmp3 = alloca %struct.selector.0, align 1
308   // CHECK-NEXT:    %call = call <40 x float> @_Z12use_matrix_2ILm4ELm6EEu11matrix_typeIXplT_Li1EEXplT0_Li2EEfERu11matrix_typeIXT_EXT0_EiE(ptr nonnull align 4 dereferenceable(96) %m1)
309   // CHECK-NEXT:    store <40 x float> %call, ptr %r1, align 4
310   // CHECK-NEXT:    call void @_Z12use_matrix_2ILm2ELm12EE8selectorILi0EERu11matrix_typeIXplT_Li2EEXdvT0_Li2EEiERu11matrix_typeIXT_EXT0_EfE(ptr nonnull align 4 dereferenceable(96) %m1, ptr nonnull align 4 dereferenceable(96) %m2)
311   // CHECK-NEXT:    call void @_Z12use_matrix_2ILm5ELm8EE8selectorILi1EERu11matrix_typeIXplT_T0_EXT0_EiERu11matrix_typeIXT_EXmiT0_T_EfE(ptr nonnull align 4 dereferenceable(416) %m3, ptr nonnull align 4 dereferenceable(60) %m4)
312   // CHECK-NEXT:    %call2 = call <20 x float> @_Z12use_matrix_2ILm5EEu11matrix_typeIXplT_T_EXmiT_Li3EEfERu11matrix_typeIXT_ELm10EiE(ptr nonnull align 4 dereferenceable(200) %m5)
313   // CHECK-NEXT:    store <20 x float> %call2, ptr %r4, align 4
314   // CHECK-NEXT:    call void @_Z12use_matrix_3ILm6EE8selectorILi2EERu11matrix_typeIXmiT_Li2EEXT_EiE(ptr nonnull align 4 dereferenceable(96) %m1)
315   // CHECK-NEXT:    ret void
316 
317   // CHECK-LABEL: define linkonce_odr <40 x float> @_Z12use_matrix_2ILm4ELm6EEu11matrix_typeIXplT_Li1EEXplT0_Li2EEfERu11matrix_typeIXT_EXT0_EiE(ptr nonnull align 4 dereferenceable(96) %m)
318   // CHECK-NEXT:  entry:
319   // CHECK-NEXT:    %m.addr = alloca ptr, align 8
320   // CHECK-NEXT:    store ptr %m, ptr %m.addr, align 8
321   // CHECK-NEXT:    call void @llvm.trap()
322   // CHECK-NEXT:    unreachable
323 
324   // CHECK-LABEL: define linkonce_odr void @_Z12use_matrix_2ILm2ELm12EE8selectorILi0EERu11matrix_typeIXplT_Li2EEXdvT0_Li2EEiERu11matrix_typeIXT_EXT0_EfE(ptr nonnull align 4 dereferenceable(96) %m1, ptr nonnull align 4 dereferenceable(96) %m2)
325   // CHECK-NEXT:  entry:
326   // CHECK-NEXT:    %m1.addr = alloca ptr, align 8
327   // CHECK-NEXT:    %m2.addr = alloca ptr, align 8
328   // CHECK-NEXT:    store ptr %m1, ptr %m1.addr, align 8
329   // CHECK-NEXT:    store ptr %m2, ptr %m2.addr, align 8
330   // CHECK-NEXT:    call void @llvm.trap()
331   // CHECK-NEXT:    unreachable
332 
333   // CHECK-LABEL: define linkonce_odr void @_Z12use_matrix_2ILm5ELm8EE8selectorILi1EERu11matrix_typeIXplT_T0_EXT0_EiERu11matrix_typeIXT_EXmiT0_T_EfE(ptr nonnull align 4 dereferenceable(416) %m1, ptr nonnull align 4 dereferenceable(60) %m2)
334   // CHECK-NEXT:  entry:
335   // CHECK-NEXT:    %m1.addr = alloca ptr, align 8
336   // CHECK-NEXT:    %m2.addr = alloca ptr, align 8
337   // CHECK-NEXT:    store ptr %m1, ptr %m1.addr, align 8
338   // CHECK-NEXT:    store ptr %m2, ptr %m2.addr, align 8
339   // CHECK-NEXT:    call void @llvm.trap()
340   // CHECK-NEXT:    unreachable
341 
342   // CHECK-LABEL: define linkonce_odr <20 x float> @_Z12use_matrix_2ILm5EEu11matrix_typeIXplT_T_EXmiT_Li3EEfERu11matrix_typeIXT_ELm10EiE(ptr nonnull align 4 dereferenceable(200) %m1)
343   // CHECK-NEXT:  entry:
344   // CHECK-NEXT:    %m1.addr = alloca ptr, align 8
345   // CHECK-NEXT:    store ptr %m1, ptr %m1.addr, align 8
346   // CHECK-NEXT:    call void @llvm.trap()
347   // CHECK-NEXT:    unreachable
348 
349   // CHECK-LABEL: define linkonce_odr void @_Z12use_matrix_3ILm6EE8selectorILi2EERu11matrix_typeIXmiT_Li2EEXT_EiE(ptr nonnull align 4 dereferenceable(96) %m)
350   // CHECK-NEXT:  entry:
351   // CHECK-NEXT:    %m.addr = alloca ptr, align 8
352   // CHECK-NEXT:    store ptr %m, ptr %m.addr, align 8
353   // CHECK-NEXT:    call void @llvm.trap()
354   // CHECK-NEXT:    unreachable
355 
356   matrix<int, 4, 6> m1;
357   matrix<float, 5, 8> r1 = use_matrix_2(m1);
358 
359   matrix<float, 2, 12> m2;
360   selector<0> r2 = use_matrix_2(m1, m2);
361 
362   matrix<int, 13, 8> m3;
363   matrix<float, 5, 3> m4;
364   selector<1> r3 = use_matrix_2(m3, m4);
365 
366   matrix<int, 5, 10> m5;
367   matrix<float, 10, 2> r4 = use_matrix_2(m5);
368 
369   selector<2> r5 = use_matrix_3(m1);
370 }
371 
372 // CHECK-LABEL: define void @_Z22test_pseudo_destructorv()
373 // CHECK-NEXT: entry:
374 // CHECK-NEXT:   %a = alloca [25 x double], align 8
375 // CHECK-NEXT:   %b = alloca [12 x float], align 4
376 // CHECK-NEXT:   %0 = load <25 x double>, ptr %a, align 8
377 // CHECK-NEXT:   call void @_Z17pseudo_destructorIu11matrix_typeILm5ELm5EdEEvT_(<25 x double> %0)
378 // CHECK-NEXT:   %1 = load <12 x float>, ptr %b, align 4
379 // CHECK-NEXT:   call void @_Z17pseudo_destructorIu11matrix_typeILm3ELm4EfEEvT_(<12 x float> %1)
380 // CHECK-NEXT:   ret void
381 
382 // CHECK-LABEL: define linkonce_odr void @_Z17pseudo_destructorIu11matrix_typeILm5ELm5EdEEvT_(<25 x double> %t)
383 // CHECK-NEXT: entry:
384 // CHECK-NEXT:   %t.addr = alloca [25 x double], align 8
385 // CHECK-NEXT:   store <25 x double> %t, ptr %t.addr, align 8
386 // CHECK-NEXT:   ret void
387 
388 // CHECK-LABEL: define linkonce_odr void @_Z17pseudo_destructorIu11matrix_typeILm3ELm4EfEEvT_(<12 x float> %t)
389 // CHECK-NEXT: entry:
390 // CHECK-NEXT:   %t.addr = alloca [12 x float], align 4
391 // CHECK-NEXT:   store <12 x float> %t, ptr %t.addr, align 4
392 // CHECK-NEXT:   ret void
393 template <typename T>
394 void pseudo_destructor(T t) {
395   t.~T();
396 }
397 
398 void test_pseudo_destructor() {
399   dx5x5_t a;
400   fx3x4_t b;
401   pseudo_destructor(a);
402   pseudo_destructor(b);
403 }
404