1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "mir_type.h"
17 #include "mir_symbol.h"
18 #include "printing.h"
19 #include "namemangler.h"
20 #include "global_tables.h"
21 #include "mir_builder.h"
22 #include "cfg_primitive_types.h"
23 #include "string_utils.h"
24 #include "triple.h"
25 #if MIR_FEATURE_FULL
26
27 namespace maple {
28 #define LOAD_PRIMARY_TYPE_PROPERTY
29 #include "prim_types.def"
30
31 #define LOAD_ALGO_PRIMARY_TYPE
GetPrimitiveTypeProperty(PrimType pType)32 const PrimitiveTypeProperty &GetPrimitiveTypeProperty(PrimType pType)
33 {
34 switch (pType) {
35 case PTY_begin:
36 return PTProperty_begin;
37 #define PRIMTYPE(P) \
38 case PTY_##P: \
39 return PTProperty_##P;
40 #include "prim_types.def"
41 #undef PRIMTYPE
42 case PTY_end:
43 default:
44 return PTProperty_end;
45 }
46 }
47
GetRegPrimType(PrimType primType)48 PrimType GetRegPrimType(PrimType primType)
49 {
50 switch (primType) {
51 case PTY_i8:
52 case PTY_i16:
53 return PTY_i32;
54 case PTY_u1:
55 case PTY_u8:
56 case PTY_u16:
57 return PTY_u32;
58 default:
59 return primType;
60 }
61 }
62
GetReg64PrimType(PrimType primType)63 PrimType GetReg64PrimType(PrimType primType)
64 {
65 switch (primType) {
66 case PTY_i8:
67 case PTY_i16:
68 case PTY_i32:
69 return PTY_i64;
70 case PTY_u1:
71 case PTY_u8:
72 case PTY_u16:
73 case PTY_u32:
74 return PTY_u64;
75 default:
76 return primType;
77 }
78 }
79
VerifyPrimType(PrimType primType1,PrimType primType2)80 bool VerifyPrimType(PrimType primType1, PrimType primType2)
81 {
82 switch (primType1) {
83 case PTY_u1:
84 case PTY_u8:
85 case PTY_u16:
86 case PTY_u32:
87 case PTY_a32:
88 return IsUnsignedInteger(primType2);
89 case PTY_i8:
90 case PTY_i16:
91 case PTY_i32:
92 return IsSignedInteger(primType2);
93 default:
94 return primType1 == primType2;
95 }
96 }
97
GetDynType(PrimType primType)98 PrimType GetDynType(PrimType primType)
99 {
100 #ifdef DYNAMICLANG
101 switch (primType) {
102 case PTY_u1:
103 return PTY_dynbool;
104 case PTY_i32:
105 return PTY_dyni32;
106 case PTY_simplestr:
107 return PTY_dynstr;
108 case PTY_simpleobj:
109 return PTY_dynobj;
110 case PTY_f32:
111 return PTY_dynf32;
112 case PTY_f64:
113 return PTY_dynf64;
114 default:
115 return primType;
116 }
117 #else
118 return primType;
119 #endif
120 }
121
GetNonDynType(PrimType primType)122 PrimType GetNonDynType(PrimType primType)
123 {
124 #ifdef DYNAMICLANG
125 switch (primType) {
126 case PTY_dynbool:
127 return PTY_u1;
128 case PTY_dyni32:
129 return PTY_i32;
130 case PTY_dynstr:
131 return PTY_simplestr;
132 case PTY_dynobj:
133 return PTY_simpleobj;
134 case PTY_dynf32:
135 return PTY_f32;
136 case PTY_dynf64:
137 return PTY_f64;
138 default:
139 return primType;
140 }
141 #else
142 return primType;
143 #endif
144 }
145
GetIntegerPrimTypeBySizeAndSign(size_t sizeBit,bool isSign)146 PrimType GetIntegerPrimTypeBySizeAndSign(size_t sizeBit, bool isSign)
147 {
148 switch (sizeBit) {
149 case k1BitSize: {
150 if (isSign) {
151 return PTY_begin; // There is no 'i1' type
152 }
153 return PTY_u1;
154 }
155 case k8BitSize: {
156 return isSign ? PTY_i8 : PTY_u8;
157 }
158 case k16BitSize: {
159 return isSign ? PTY_i16 : PTY_u16;
160 }
161 case k32BitSize: {
162 return isSign ? PTY_i32 : PTY_u32;
163 }
164 case k64BitSize: {
165 return isSign ? PTY_i64 : PTY_u64;
166 }
167 default: {
168 return PTY_begin; // Invalid integer type
169 }
170 }
171 }
172
IsNoCvtNeeded(PrimType toType,PrimType fromType)173 bool IsNoCvtNeeded(PrimType toType, PrimType fromType)
174 {
175 if (toType == fromType) {
176 return true;
177 }
178 switch (toType) {
179 case PTY_i32:
180 return fromType == PTY_i16 || fromType == PTY_i8;
181 case PTY_u32:
182 return fromType == PTY_u16 || fromType == PTY_u8;
183 case PTY_u1:
184 case PTY_u8:
185 case PTY_u16:
186 return fromType == PTY_u32;
187 case PTY_i8:
188 case PTY_i16:
189 return fromType == PTY_i32;
190 case PTY_i64:
191 case PTY_u64:
192 case PTY_a64:
193 case PTY_ptr:
194 return fromType == PTY_ptr || fromType == PTY_u64 || fromType == PTY_a64 || fromType == PTY_i64;
195 default:
196 return false;
197 }
198 }
199
NeedCvtOrRetype(PrimType origin,PrimType compared)200 bool NeedCvtOrRetype(PrimType origin, PrimType compared)
201 {
202 return GetPrimTypeSize(origin) != GetPrimTypeSize(compared) || IsSignedInteger(origin) != IsSignedInteger(compared);
203 }
204
GetPointerSize()205 uint8 GetPointerSize()
206 {
207 #if TARGX86 || TARGARM32 || TARGVM
208 return k4ByteSize;
209 #elif TARGX86_64 || TARGAARCH64
210 if (Triple::GetTriple().GetArch() == Triple::ArchType::x64) {
211 return k8ByteSize;
212 } else if (Triple::GetTriple().GetArch() == Triple::ArchType::aarch64) {
213 uint8 size = (Triple::GetTriple().GetEnvironment() == Triple::GNUILP32) ? k4ByteSize : k8ByteSize;
214 return size;
215 } else {
216 CHECK_FATAL(false, "Unsupported target");
217 }
218 #else
219 #error "Unsupported target"
220 #endif
221 }
222
GetP2Size()223 uint8 GetP2Size()
224 {
225 #if TARGX86 || TARGARM32 || TARGVM
226 return k2ByteSize;
227 #elif TARGX86_64 || TARGAARCH64
228 if (Triple::GetTriple().GetArch() == Triple::ArchType::x64) {
229 return k3ByteSize;
230 } else if (Triple::GetTriple().GetArch() == Triple::ArchType::aarch64) {
231 uint8 size = (Triple::GetTriple().GetEnvironment() == Triple::GNUILP32) ? k2ByteSize : k3ByteSize;
232 return size;
233 } else {
234 CHECK_FATAL(false, "Unsupported target");
235 }
236 #else
237 #error "Unsupported target"
238 #endif
239 }
240
GetLoweredPtrType()241 PrimType GetLoweredPtrType()
242 {
243 #if TARGX86 || TARGARM32 || TARGVM
244 return PTY_a32;
245 #elif TARGX86_64 || TARGAARCH64
246 if (Triple::GetTriple().GetArch() == Triple::ArchType::x64) {
247 return PTY_a64;
248 } else if (Triple::GetTriple().GetArch() == Triple::ArchType::aarch64) {
249 auto pty = (Triple::GetTriple().GetEnvironment() == Triple::GNUILP32) ? PTY_a32 : PTY_a64;
250 return pty;
251 } else {
252 CHECK_FATAL(false, "Unsupported target");
253 }
254 #else
255 #error "Unsupported target"
256 #endif
257 }
258
GetExactPtrPrimType()259 PrimType GetExactPtrPrimType()
260 {
261 return (GetPointerSize() == k8ByteSize) ? PTY_a64 : PTY_a32;
262 }
263
264 // answer in bytes; 0 if unknown
GetPrimTypeSize(PrimType primType)265 uint32 GetPrimTypeSize(PrimType primType)
266 {
267 switch (primType) {
268 case PTY_void:
269 case PTY_agg:
270 return k0BitSize;
271 case PTY_ptr:
272 case PTY_ref:
273 return GetPointerSize();
274 case PTY_u1:
275 case PTY_i8:
276 case PTY_u8:
277 return k1BitSize;
278 case PTY_i16:
279 case PTY_u16:
280 return k2BitSize;
281 case PTY_a32:
282 case PTY_f32:
283 case PTY_i32:
284 case PTY_u32:
285 case PTY_simplestr:
286 case PTY_simpleobj:
287 return k4BitSize;
288 case PTY_a64:
289 case PTY_c64:
290 case PTY_f64:
291 case PTY_i64:
292 case PTY_u64:
293 case PTY_v2i32:
294 case PTY_v4i16:
295 case PTY_v8i8:
296 case PTY_v2u32:
297 case PTY_v4u16:
298 case PTY_v8u8:
299 case PTY_v2f32:
300 return k8BitSize;
301 case PTY_u128:
302 case PTY_i128:
303 case PTY_c128:
304 case PTY_f128:
305 case PTY_v2i64:
306 case PTY_v4i32:
307 case PTY_v8i16:
308 case PTY_v16i8:
309 case PTY_v2u64:
310 case PTY_v4u32:
311 case PTY_v8u16:
312 case PTY_v16u8:
313 case PTY_v2f64:
314 case PTY_v4f32:
315 return k16BitSize;
316 #ifdef DYNAMICLANG
317 case PTY_dynf32:
318 case PTY_dyni32:
319 case PTY_dynstr:
320 case PTY_dynobj:
321 case PTY_dynundef:
322 case PTY_dynnull:
323 case PTY_dynbool:
324 return k8BitSize;
325 case PTY_dynany:
326 case PTY_dynf64:
327 return k8BitSize;
328 #endif
329 default:
330 return k0BitSize;
331 }
332 }
333
334 // answer is n if size in byte is (1<<n) (0: 1B; 1: 2B, 2: 4B, 3: 8B, 4:16B)
GetPrimTypeP2Size(PrimType primType)335 uint32 GetPrimTypeP2Size(PrimType primType)
336 {
337 switch (primType) {
338 case PTY_ptr:
339 case PTY_ref:
340 return GetP2Size();
341 case PTY_u1:
342 case PTY_i8:
343 case PTY_u8:
344 return k0BitSize;
345 case PTY_i16:
346 case PTY_u16:
347 return k1BitSize;
348 case PTY_a32:
349 case PTY_f32:
350 case PTY_i32:
351 case PTY_u32:
352 case PTY_simplestr:
353 case PTY_simpleobj:
354 return k2BitSize;
355 case PTY_a64:
356 case PTY_c64:
357 case PTY_f64:
358 case PTY_i64:
359 case PTY_u64:
360 case PTY_v2i32:
361 case PTY_v4i16:
362 case PTY_v8i8:
363 case PTY_v2u32:
364 case PTY_v4u16:
365 case PTY_v8u8:
366 case PTY_v2f32:
367 return k3BitSize;
368 case PTY_c128:
369 case PTY_f128:
370 case PTY_v2i64:
371 case PTY_v4i32:
372 case PTY_v8i16:
373 case PTY_v16i8:
374 case PTY_v2u64:
375 case PTY_v4u32:
376 case PTY_v8u16:
377 case PTY_v16u8:
378 case PTY_v2f64:
379 case PTY_v4f32:
380 return k4BitSize;
381 #ifdef DYNAMICLANG
382 case PTY_dynf32:
383 case PTY_dyni32:
384 case PTY_dynstr:
385 case PTY_dynobj:
386 case PTY_dynundef:
387 case PTY_dynnull:
388 case PTY_dynbool:
389 case PTY_dynany:
390 case PTY_dynf64:
391 return k3BitSize;
392 #endif
393 default:
394 DEBUG_ASSERT(false, "Power-of-2 size only applicable to sizes of 1, 2, 4, 8 or 16 bytes.");
395 return k10BitSize;
396 }
397 }
398
GetVecEleSize(PrimType primType)399 uint32 GetVecEleSize(PrimType primType)
400 {
401 switch (primType) {
402 case PTY_v2i64:
403 case PTY_v2u64:
404 case PTY_v2f64:
405 case PTY_i64:
406 case PTY_u64:
407 case PTY_f64:
408 return k64BitSize;
409 case PTY_v2i32:
410 case PTY_v2u32:
411 case PTY_v2f32:
412 case PTY_v4i32:
413 case PTY_v4u32:
414 case PTY_v4f32:
415 return k32BitSize;
416 case PTY_v4i16:
417 case PTY_v4u16:
418 case PTY_v8i16:
419 case PTY_v8u16:
420 return k16BitSize;
421 case PTY_v8i8:
422 case PTY_v8u8:
423 case PTY_v16i8:
424 case PTY_v16u8:
425 return k8BitSize;
426 default:
427 CHECK_FATAL(false, "unexpected primtType for vector");
428 }
429 }
430
GetVecLanes(PrimType primType)431 uint32 GetVecLanes(PrimType primType)
432 {
433 switch (primType) {
434 case PTY_v2i32:
435 case PTY_v2u32:
436 case PTY_v2f32:
437 case PTY_v2i64:
438 case PTY_v2u64:
439 case PTY_v2f64:
440 return k2BitSize;
441 case PTY_v4i16:
442 case PTY_v4u16:
443 case PTY_v4i32:
444 case PTY_v4u32:
445 case PTY_v4f32:
446 return k4BitSize;
447 case PTY_v8i8:
448 case PTY_v8u8:
449 case PTY_v8i16:
450 case PTY_v8u16:
451 return k8BitSize;
452 case PTY_v16i8:
453 case PTY_v16u8:
454 return k16BitSize;
455 default:
456 return 0;
457 }
458 }
459
GetVecElemPrimType(PrimType primType)460 PrimType GetVecElemPrimType(PrimType primType)
461 {
462 switch (primType) {
463 case PTY_v2i32:
464 case PTY_v4i32:
465 return PTY_i32;
466 case PTY_v2u32:
467 case PTY_v4u32:
468 return PTY_u32;
469 case PTY_v2i64:
470 return PTY_i64;
471 case PTY_v2u64:
472 return PTY_u64;
473 case PTY_v16i8:
474 case PTY_v8i8:
475 return PTY_i8;
476 case PTY_v16u8:
477 case PTY_v8u8:
478 return PTY_u8;
479 case PTY_v8i16:
480 case PTY_v4i16:
481 return PTY_i16;
482 case PTY_v8u16:
483 case PTY_v4u16:
484 return PTY_u16;
485 case PTY_v2f32:
486 case PTY_v4f32:
487 return PTY_f32;
488 case PTY_v2f64:
489 return PTY_f64;
490 default:
491 return PTY_begin; // not a vector type
492 }
493 return PTY_begin; // not a vector type
494 }
495
496 // return the signed version that has the same size
GetSignedPrimType(PrimType pty)497 PrimType GetSignedPrimType(PrimType pty)
498 {
499 switch (pty) {
500 case PTY_ptr:
501 case PTY_ref:
502 case PTY_a64:
503 case PTY_u64:
504 return PTY_i64;
505 case PTY_u8:
506 return PTY_i8;
507 case PTY_u16:
508 return PTY_i16;
509 case PTY_a32:
510 case PTY_u32:
511 return PTY_i32;
512 default:;
513 }
514 return pty;
515 }
516
517 // return the unsigned version that has the same size
GetUnsignedPrimType(PrimType pty)518 PrimType GetUnsignedPrimType(PrimType pty)
519 {
520 switch (pty) {
521 case PTY_i64:
522 return PTY_u64;
523 case PTY_i8:
524 return PTY_u8;
525 case PTY_i16:
526 return PTY_u16;
527 case PTY_i32:
528 return PTY_u32;
529 default:;
530 }
531 return pty;
532 }
533
MinValOfSignedInteger(PrimType primType)534 int64 MinValOfSignedInteger(PrimType primType)
535 {
536 switch (primType) {
537 case PTY_i8:
538 return INT8_MIN;
539 case PTY_i16:
540 return INT16_MIN;
541 case PTY_i32:
542 return INT32_MIN;
543 case PTY_i64:
544 return INT64_MIN;
545 default:
546 CHECK_FATAL(false, "NIY");
547 return 0;
548 }
549 }
550
GetPrimTypeName(PrimType primType)551 const char *GetPrimTypeName(PrimType primType)
552 {
553 #define LOAD_ALGO_PRIMARY_TYPE
554 switch (primType) {
555 case kPtyInvalid:
556 return "kPtyInvalid";
557 #define PRIMTYPE(P) \
558 case PTY_##P: \
559 return #P;
560 #include "prim_types.def"
561 #undef PRIMTYPE
562 case kPtyDerived:
563 return "derived"; // just for test: no primitive type for derived
564 default:
565 return "kPtyInvalid";
566 }
567 // SIMD types to be defined
568 }
569
DumpAttributes() const570 void StmtAttrs::DumpAttributes() const
571 {
572 #define STMT_ATTR
573 #define STRING(s) #s
574 #define ATTR(AT) \
575 if (GetAttr(STMTATTR_##AT)) \
576 LogInfo::MapleLogger() << STRING(AT);
577 #include "all_attributes.def"
578 #undef ATTR
579 #undef STMT_ATTR
580 }
581
DumpAttributes() const582 void TypeAttrs::DumpAttributes() const
583 {
584 // dump attr without content
585 #define TYPE_ATTR
586 #define NOCONTENT_ATTR
587 #define STRING(s) #s
588 #define ATTR(AT) \
589 if (GetAttr(ATTR_##AT)) \
590 LogInfo::MapleLogger() << " " << STRING(AT);
591 #include "all_attributes.def"
592 #undef ATTR
593 #undef NOCONTENT_ATTR
594 #undef TYPE_ATTR
595 // dump attr with content
596 if (attrAlign) {
597 LogInfo::MapleLogger() << " align(" << GetAlign() << ")";
598 }
599 if (GetAttr(ATTR_pack) && GetPack() != 0) {
600 LogInfo::MapleLogger() << " pack(" << GetPack() << ")";
601 }
602 }
603
DumpAttributes() const604 void FieldAttrs::DumpAttributes() const
605 {
606 // dump attr without content
607 #define FIELD_ATTR
608 #define NOCONTENT_ATTR
609 #define STRING(s) #s
610 #define ATTR(AT) \
611 if (GetAttr(FLDATTR_##AT)) \
612 LogInfo::MapleLogger() << " " << STRING(AT);
613 #include "all_attributes.def"
614 #undef ATTR
615 #undef NOCONTENT_ATTR
616 #undef FIELD_ATTR
617 // dump attr with content
618 if (attrAlign) {
619 LogInfo::MapleLogger() << " align(" << GetAlign() << ")";
620 }
621 if (IsPacked()) {
622 LogInfo::MapleLogger() << " pack(1)";
623 }
624 }
625
GetName() const626 const std::string &MIRType::GetName() const
627 {
628 return GlobalTables::GetStrTable().GetStringFromStrIdx(nameStrIdx);
629 }
630
ValidateClassOrInterface(const std::string & className,bool noWarning) const631 bool MIRType::ValidateClassOrInterface(const std::string &className, bool noWarning) const
632 {
633 if (primType == maple::PTY_agg && (typeKind == maple::kTypeClass || typeKind == maple::kTypeInterface) &&
634 nameStrIdx != 0u) {
635 return true;
636 }
637 if (!noWarning) {
638 size_t len = className.size();
639 constexpr int minClassNameLen = 4;
640 constexpr char suffix[] = "_3B";
641 size_t suffixLen = std::strlen(suffix);
642 if (len > minClassNameLen && strncmp(className.c_str() + len - suffixLen, suffix, suffixLen) == 0) {
643 LogInfo::MapleLogger(kLlErr) << "error: missing proper mplt file for " << className << '\n';
644 } else {
645 LogInfo::MapleLogger(kLlErr) << "internal error: type is not j class or interface " << className << '\n';
646 }
647 }
648 return false;
649 }
650
PointsToConstString() const651 bool MIRType::PointsToConstString() const
652 {
653 return (typeKind == kTypePointer) ? static_cast<const MIRPtrType *>(this)->PointsToConstString() : false;
654 }
655
GetMplTypeName() const656 std::string MIRType::GetMplTypeName() const
657 {
658 if (typeKind == kTypeScalar) {
659 return GetPrimTypeName(primType);
660 }
661 return "";
662 }
663
GetCompactMplTypeName() const664 std::string MIRType::GetCompactMplTypeName() const
665 {
666 return "";
667 }
668
Dump(int indent,bool dontUseName) const669 void MIRType::Dump(int indent, bool dontUseName) const
670 {
671 LogInfo::MapleLogger() << GetPrimTypeName(primType);
672 }
673
DumpAsCxx(int indent) const674 void MIRType::DumpAsCxx(int indent) const
675 {
676 switch (primType) {
677 case PTY_void:
678 LogInfo::MapleLogger() << "void";
679 break;
680 case PTY_i8:
681 LogInfo::MapleLogger() << "int8 ";
682 break;
683 case PTY_i16:
684 LogInfo::MapleLogger() << "int16";
685 break;
686 case PTY_i32:
687 LogInfo::MapleLogger() << "int32";
688 break;
689 case PTY_i64:
690 LogInfo::MapleLogger() << "int64";
691 break;
692 case PTY_u8:
693 LogInfo::MapleLogger() << "uint8";
694 break;
695 case PTY_u16:
696 LogInfo::MapleLogger() << "uint16";
697 break;
698 case PTY_u32:
699 LogInfo::MapleLogger() << "uint32";
700 break;
701 case PTY_u64:
702 LogInfo::MapleLogger() << "uint64";
703 break;
704 case PTY_u1:
705 LogInfo::MapleLogger() << "bool ";
706 break;
707 case PTY_ptr:
708 LogInfo::MapleLogger() << "void* ";
709 break;
710 case PTY_ref:
711 LogInfo::MapleLogger() << "void* ";
712 break;
713 case PTY_a32:
714 LogInfo::MapleLogger() << "int32";
715 break;
716 case PTY_a64:
717 LogInfo::MapleLogger() << "void* ";
718 break;
719 case PTY_f32:
720 LogInfo::MapleLogger() << "float ";
721 break;
722 case PTY_f64:
723 LogInfo::MapleLogger() << "double";
724 break;
725 case PTY_c64:
726 LogInfo::MapleLogger() << "float complex";
727 break;
728 case PTY_c128:
729 LogInfo::MapleLogger() << "double complex";
730 break;
731 default:
732 DEBUG_ASSERT(false, "not yet implemented");
733 }
734 }
735
IsOfSameType(MIRType & type)736 bool MIRType::IsOfSameType(MIRType &type)
737 {
738 if (typeKind != type.typeKind) {
739 return false;
740 }
741
742 if (typeKind == kTypePointer) {
743 const auto &ptrType = static_cast<const MIRPtrType &>(*this);
744 const auto &ptrTypeIt = static_cast<const MIRPtrType &>(type);
745 if (ptrType.GetPointedTyIdx() == ptrTypeIt.GetPointedTyIdx()) {
746 return true;
747 } else {
748 MIRType &mirTypeIt = *GlobalTables::GetTypeTable().GetTypeFromTyIdx(ptrTypeIt.GetPointedTyIdx());
749 return GlobalTables::GetTypeTable().GetTypeFromTyIdx(ptrType.GetPointedTyIdx())->IsOfSameType(mirTypeIt);
750 }
751 } else if (typeKind == kTypeJArray) {
752 auto &arrType1 = static_cast<MIRJarrayType &>(*this);
753 auto &arrType2 = static_cast<MIRJarrayType &>(type);
754 if (arrType1.GetDim() != arrType2.GetDim()) {
755 return false;
756 }
757 return arrType1.GetElemType()->IsOfSameType(*arrType2.GetElemType());
758 } else {
759 return tyIdx == type.tyIdx;
760 }
761 }
762
DumpTypeName(GStrIdx strIdx,bool isLocal)763 inline void DumpTypeName(GStrIdx strIdx, bool isLocal)
764 {
765 LogInfo::MapleLogger() << ((isLocal) ? "%" : "$") << GlobalTables::GetStrTable().GetStringFromStrIdx(strIdx);
766 }
767
CheckAndDumpTypeName(GStrIdx strIdx,bool isLocal)768 static bool CheckAndDumpTypeName(GStrIdx strIdx, bool isLocal)
769 {
770 if (strIdx == 0u) {
771 return false;
772 }
773 LogInfo::MapleLogger() << "<";
774 DumpTypeName(strIdx, isLocal);
775 LogInfo::MapleLogger() << ">";
776 return true;
777 }
778
Dump(int indent,bool dontUseName) const779 void MIRFuncType::Dump(int indent, bool dontUseName) const
780 {
781 if (!dontUseName && CheckAndDumpTypeName(nameStrIdx, nameIsLocal)) {
782 return;
783 }
784 LogInfo::MapleLogger() << "<func";
785 funcAttrs.DumpAttributes();
786 LogInfo::MapleLogger() << " (";
787 size_t size = paramTypeList.size();
788 for (size_t i = 0; i < size; ++i) {
789 GlobalTables::GetTypeTable().GetTypeFromTyIdx(paramTypeList[i])->Dump(indent + 1);
790 if (i < paramAttrsList.size()) {
791 paramAttrsList[i].DumpAttributes();
792 }
793 if (size - 1 != i) {
794 LogInfo::MapleLogger() << ",";
795 }
796 }
797 if (IsVarargs()) {
798 LogInfo::MapleLogger() << ", ...";
799 }
800 LogInfo::MapleLogger() << ") ";
801 GlobalTables::GetTypeTable().GetTypeFromTyIdx(retTyIdx)->Dump(indent + 1);
802 retAttrs.DumpAttributes();
803 LogInfo::MapleLogger() << ">";
804 }
805
RoundUpConst(uint64 offset,uint32 align)806 static constexpr uint64 RoundUpConst(uint64 offset, uint32 align)
807 {
808 uint64 tempFirst = static_cast<uint64>(-align);
809 CHECK_FATAL((offset <= UINT64_MAX - align), "must not be zero");
810 DEBUG_ASSERT(offset + align > 0, "offset and align should not be zero");
811 uint64 tempSecond = static_cast<uint64>(offset + align - 1);
812 return tempFirst & tempSecond;
813 }
814
RoundUp(uint64 offset,uint32 align)815 static inline uint64 RoundUp(uint64 offset, uint32 align)
816 {
817 if (align == 0) {
818 return offset;
819 }
820 return RoundUpConst(offset, align);
821 }
822
RoundDownConst(uint64 offset,uint32 align)823 static constexpr uint64 RoundDownConst(uint64 offset, uint32 align)
824 {
825 uint64 temp = static_cast<uint64>(-align);
826 return temp & offset;
827 }
828
RoundDown(uint64 offset,uint32 align)829 static inline uint64 RoundDown(uint64 offset, uint32 align)
830 {
831 if (align == 0) {
832 return offset;
833 }
834 return RoundDownConst(offset, align);
835 }
836
GetSize() const837 size_t MIRArrayType::GetSize() const
838 {
839 if (size != kInvalidSize) {
840 return size;
841 }
842 size_t elemsize = GetElemType()->GetSize();
843 if (elemsize == 0) {
844 return 0;
845 }
846 elemsize = RoundUp(elemsize, typeAttrs.GetAlign());
847 size_t numelems = sizeArray[0];
848 for (uint16 i = 1; i < dim; i++) {
849 numelems *= sizeArray[i];
850 }
851 size = elemsize * numelems;
852 return size;
853 }
854
GetAlign() const855 uint32 MIRArrayType::GetAlign() const
856 {
857 if (GetSize() == 0) {
858 return typeAttrs.GetAlign();
859 }
860 return std::max(GetElemType()->GetAlign(), typeAttrs.GetAlign());
861 }
862
Dump(int indent,bool dontUseName) const863 void MIRArrayType::Dump(int indent, bool dontUseName) const
864 {
865 if (!dontUseName && CheckAndDumpTypeName(nameStrIdx, nameIsLocal)) {
866 return;
867 }
868 LogInfo::MapleLogger() << "<";
869 for (uint16 i = 0; i < dim; ++i) {
870 LogInfo::MapleLogger() << "[" << GetSizeArrayItem(i) << "]";
871 }
872 LogInfo::MapleLogger() << " ";
873 GlobalTables::GetTypeTable().GetTypeFromTyIdx(eTyIdx)->Dump(indent + 1);
874 GetTypeAttrs().DumpAttributes();
875 LogInfo::MapleLogger() << ">";
876 }
877
GetCompactMplTypeName() const878 std::string MIRArrayType::GetCompactMplTypeName() const
879 {
880 std::stringstream ss;
881 ss << "A";
882 MIRType *elemType = GetElemType();
883 ss << elemType->GetCompactMplTypeName();
884 return ss.str();
885 }
886
Dump(int indent,bool dontUseName) const887 void MIRFarrayType::Dump(int indent, bool dontUseName) const
888 {
889 if (!dontUseName && CheckAndDumpTypeName(nameStrIdx, nameIsLocal)) {
890 return;
891 }
892 LogInfo::MapleLogger() << "<[] ";
893 GlobalTables::GetTypeTable().GetTypeFromTyIdx(elemTyIdx)->Dump(indent + 1);
894 LogInfo::MapleLogger() << ">";
895 }
896
GetCompactMplTypeName() const897 std::string MIRFarrayType::GetCompactMplTypeName() const
898 {
899 std::stringstream ss;
900 ss << "A";
901 MIRType *elemType = GetElemType();
902 ss << elemType->GetCompactMplTypeName();
903 return ss.str();
904 }
905
GetParentType()906 MIRStructType *MIRJarrayType::GetParentType()
907 {
908 return static_cast<MIRStructType *>(GlobalTables::GetTypeTable().GetTypeFromTyIdx(parentTyIdx));
909 }
910
DetermineName()911 void MIRJarrayType::DetermineName()
912 {
913 if (jNameStrIdx != 0u) {
914 return; // already determined
915 }
916 MIRType *elemType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(GetElemTyIdx());
917 dim = 1;
918 std::string baseName;
919 while (true) {
920 if (elemType->GetKind() == kTypePointer) {
921 auto *pType = static_cast<MIRPtrType *>(elemType)->GetPointedType();
922 DEBUG_ASSERT(pType != nullptr, "pType is null in MIRJarrayType::DetermineName");
923 if (pType->GetKind() == kTypeByName || pType->GetKind() == kTypeClass ||
924 pType->GetKind() == kTypeInterface || pType->GetKind() == kTypeClassIncomplete ||
925 pType->GetKind() == kTypeInterfaceIncomplete) {
926 baseName = static_cast<MIRStructType *>(pType)->GetName();
927 fromPrimitive = false;
928 break;
929 } else if (pType->GetKind() == kTypeJArray) {
930 auto *tmpPtype = static_cast<MIRJarrayType *>(pType);
931 elemType = tmpPtype->GetElemType();
932 DEBUG_ASSERT(elemType != nullptr, "elemType is null in MIRJarrayType::DetermineName");
933 ++dim;
934 } else {
935 DEBUG_ASSERT(false, "unexpected type!");
936 }
937 } else {
938 DEBUG_ASSERT(false, "unexpected type!");
939 }
940 }
941 std::string name;
942 for (int i = dim; i > 0; --i) {
943 name += JARRAY_PREFIX_STR;
944 }
945 name += baseName;
946 jNameStrIdx = GlobalTables::GetStrTable().GetOrCreateStrIdxFromName(name);
947 }
948
GetPointedType() const949 MIRType *MIRPtrType::GetPointedType() const
950 {
951 return GlobalTables::GetTypeTable().GetTypeFromTyIdx(pointedTyIdx);
952 }
953
IsVolatile(int fieldID) const954 bool MIRType::IsVolatile(int fieldID) const
955 {
956 if (fieldID == 0) {
957 return HasVolatileField();
958 }
959 return static_cast<const MIRStructType *>(this)->IsFieldVolatile(fieldID);
960 }
961
HasTypeParam() const962 bool MIRPtrType::HasTypeParam() const
963 {
964 return GetPointedType()->HasTypeParam();
965 }
966
PointsToConstString() const967 bool MIRPtrType::PointsToConstString() const
968 {
969 return false;
970 }
971
Dump(int indent,bool dontUseName) const972 void MIRPtrType::Dump(int indent, bool dontUseName) const
973 {
974 if (!dontUseName && CheckAndDumpTypeName(nameStrIdx, nameIsLocal)) {
975 return;
976 }
977 MIRType *pointedType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(pointedTyIdx);
978 if (pointedType->GetKind() == kTypeFunction) { // no * for function pointer
979 pointedType->Dump(indent);
980 } else {
981 LogInfo::MapleLogger() << "<* ";
982 pointedType->Dump(indent + 1);
983 typeAttrs.DumpAttributes();
984 LogInfo::MapleLogger() << ">";
985 }
986 }
987
Dump(int indent,bool dontUseName) const988 void MIRBitFieldType::Dump(int indent, bool dontUseName) const
989 {
990 LogInfo::MapleLogger() << ":" << static_cast<int>(fieldSize) << " " << GetPrimTypeName(primType);
991 }
992
GetSize() const993 size_t MIRClassType::GetSize() const
994 {
995 if (parentTyIdx == 0u) {
996 return MIRStructType::GetSize();
997 }
998 if (size != kInvalidSize) {
999 return size;
1000 }
1001 const auto *parentType =
1002 static_cast<const MIRClassType *>(GlobalTables::GetTypeTable().GetTypeFromTyIdx(parentTyIdx));
1003 size_t parentSize = parentType->GetSize();
1004 if (parentSize == 0) {
1005 return 0;
1006 }
1007 size_t structSize = MIRStructType::GetSize();
1008 if (structSize == 0) {
1009 return 0;
1010 }
1011 size = parentSize + structSize;
1012 return size;
1013 }
1014
GetFirstLocalFieldID() const1015 FieldID MIRClassType::GetFirstLocalFieldID() const
1016 {
1017 if (!IsLocal()) {
1018 return 0;
1019 }
1020 if (parentTyIdx == 0u) {
1021 return 1;
1022 }
1023
1024 constexpr uint8 lastFieldIDOffset = 2;
1025 constexpr uint8 firstLocalFieldIDOffset = 1;
1026 const auto *parentClassType =
1027 static_cast<const MIRClassType *>(GlobalTables::GetTypeTable().GetTypeFromTyIdx(parentTyIdx));
1028 return !parentClassType->IsLocal() ? parentClassType->GetLastFieldID() + lastFieldIDOffset
1029 : parentClassType->GetFirstLocalFieldID() + firstLocalFieldIDOffset;
1030 }
1031
GetLastFieldID() const1032 FieldID MIRClassType::GetLastFieldID() const
1033 {
1034 FieldID fieldID = static_cast<int32>(fields.size());
1035 if (parentTyIdx != 0u) {
1036 const auto *parentClassType =
1037 static_cast<const MIRClassType *>(GlobalTables::GetTypeTable().GetTypeFromTyIdx(parentTyIdx));
1038 if (parentClassType != nullptr) {
1039 fieldID += parentClassType->GetLastFieldID() + 1;
1040 }
1041 }
1042 return fieldID;
1043 }
1044
DumpClassOrInterfaceInfo(const MIRStructType & type,int indent)1045 static void DumpClassOrInterfaceInfo(const MIRStructType &type, int indent)
1046 {
1047 const std::vector<MIRInfoPair> &info = type.GetInfo();
1048 std::vector<bool> infoIsString = type.GetInfoIsString();
1049 size_t size = info.size();
1050 for (size_t i = 0; i < size; ++i) {
1051 LogInfo::MapleLogger() << '\n';
1052 PrintIndentation(indent);
1053 LogInfo::MapleLogger() << "@" << GlobalTables::GetStrTable().GetStringFromStrIdx(info[i].first) << " ";
1054 if (!infoIsString[i]) {
1055 LogInfo::MapleLogger() << info[i].second;
1056 } else {
1057 LogInfo::MapleLogger() << "\"" << GlobalTables::GetStrTable().GetStringFromStrIdx(GStrIdx(info[i].second))
1058 << "\"";
1059 }
1060 if (i != size - 1) {
1061 LogInfo::MapleLogger() << ",";
1062 }
1063 }
1064 }
1065
GetInfoFromStrIdx(const std::vector<MIRInfoPair> & info,const GStrIdx & strIdx)1066 static uint32 GetInfoFromStrIdx(const std::vector<MIRInfoPair> &info, const GStrIdx &strIdx)
1067 {
1068 for (MIRInfoPair infoPair : info) {
1069 if (infoPair.first == strIdx) {
1070 return infoPair.second;
1071 }
1072 }
1073 return 0;
1074 }
1075
GetInfo(GStrIdx strIdx) const1076 uint32 MIRInterfaceType::GetInfo(GStrIdx strIdx) const
1077 {
1078 return GetInfoFromStrIdx(info, strIdx);
1079 }
1080
1081 // return class id or superclass id accroding to input string
GetInfo(const std::string & infoStr) const1082 uint32 MIRInterfaceType::GetInfo(const std::string &infoStr) const
1083 {
1084 GStrIdx strIdx = GlobalTables::GetStrTable().GetStrIdxFromName(infoStr);
1085 return GetInfo(strIdx);
1086 }
GetSize() const1087 size_t MIRInterfaceType::GetSize() const
1088 {
1089 if (size != kInvalidSize) {
1090 return size;
1091 }
1092 size = MIRStructType::GetSize();
1093 if (parentsTyIdx.empty()) {
1094 return size;
1095 }
1096 if (size == 0) {
1097 return 0;
1098 }
1099 for (size_t i = 0; i < parentsTyIdx.size(); ++i) {
1100 const auto *parentType =
1101 static_cast<const MIRInterfaceType *>(GlobalTables::GetTypeTable().GetTypeFromTyIdx(parentsTyIdx[i]));
1102 size_t parentSize = parentType->GetSize();
1103 if (parentSize == 0) {
1104 return 0;
1105 }
1106 size += parentSize;
1107 }
1108 return size;
1109 }
1110
DumpStaticValue(const MIREncodedArray & staticValue,int indent)1111 static void DumpStaticValue(const MIREncodedArray &staticValue, int indent)
1112 {
1113 if (staticValue.empty()) {
1114 return;
1115 }
1116 LogInfo::MapleLogger() << '\n';
1117 PrintIndentation(indent);
1118 LogInfo::MapleLogger() << "@staticvalue";
1119 constexpr uint32 typeLen = 5;
1120 constexpr uint32 typeMask = 0x1f;
1121 for (const auto &value : staticValue) {
1122 LogInfo::MapleLogger() << " [";
1123 uint8 valueArg = static_cast<uint32>(value.encodedValue[0]) >> typeLen;
1124 uint8 valueType = static_cast<uint32>(value.encodedValue[0]) & typeMask;
1125 // kValueNull kValueBoolean
1126 constexpr uint32 simpleOffset = 1;
1127 constexpr uint32 aggOffSet = 2;
1128 valueArg = (valueType == kValueNull || valueType == kValueBoolean) ? simpleOffset : valueArg + aggOffSet;
1129 for (uint32 k = 0; k < valueArg; ++k) {
1130 LogInfo::MapleLogger() << static_cast<uint32>(value.encodedValue[k]);
1131 if (k != static_cast<uint32>(valueArg - 1)) {
1132 LogInfo::MapleLogger() << " ";
1133 }
1134 }
1135 LogInfo::MapleLogger() << "]";
1136 }
1137 }
1138
DumpFields(FieldVector fields,int indent,bool otherFields=false)1139 static void DumpFields(FieldVector fields, int indent, bool otherFields = false)
1140 {
1141 size_t size = fields.size();
1142 for (size_t i = 0; i < size; ++i) {
1143 LogInfo::MapleLogger() << '\n';
1144 PrintIndentation(indent);
1145 LogInfo::MapleLogger() << ((!otherFields) ? "@" : "^")
1146 << GlobalTables::GetStrTable().GetStringFromStrIdx(fields[i].first) << " ";
1147 GlobalTables::GetTypeTable().GetTypeFromTyIdx(fields[i].second.first)->Dump(indent + 1);
1148 FieldAttrs &fa = fields[i].second.second;
1149 fa.DumpAttributes();
1150 if (fa.GetAttr(FLDATTR_static) && fa.GetAttr(FLDATTR_final) &&
1151 (fa.GetAttr(FLDATTR_public) || fa.GetAttr(FLDATTR_protected))) {
1152 const char *fieldName = GlobalTables::GetStrTable().GetStringFromStrIdx(fields[i].first).c_str();
1153 MIRSymbol *fieldVar = GlobalTables::GetGsymTable().GetSymbolFromStrIdx(
1154 GlobalTables::GetStrTable().GetStrIdxFromName(fieldName));
1155 if (fieldVar != nullptr && fieldVar->GetKonst() != nullptr &&
1156 fieldVar->GetKonst()->GetKind() == kConstStr16Const) {
1157 LogInfo::MapleLogger() << " = ";
1158 fieldVar->GetKonst()->Dump();
1159 }
1160 }
1161 if (i != size - 1) {
1162 LogInfo::MapleLogger() << ",";
1163 }
1164 }
1165 }
1166
DumpFieldsAsCxx(const FieldVector & fields,int indent)1167 static void DumpFieldsAsCxx(const FieldVector &fields, int indent)
1168 {
1169 for (auto &f : fields) {
1170 PrintIndentation(indent);
1171 const FieldAttrs &fa = f.second.second;
1172 if (fa.GetAttr(FLDATTR_static)) {
1173 LogInfo::MapleLogger() << "// ";
1174 }
1175 LogInfo::MapleLogger() << "/* ";
1176 fa.DumpAttributes();
1177 GlobalTables::GetTypeTable().GetTypeFromTyIdx(f.second.first)->Dump(indent + 1);
1178 LogInfo::MapleLogger() << " */ ";
1179 GlobalTables::GetTypeTable().GetTypeFromTyIdx(f.second.first)->DumpAsCxx(indent + 1);
1180 LogInfo::MapleLogger() << " " << GlobalTables::GetStrTable().GetStringFromStrIdx(f.first) << ";" << '\n';
1181 }
1182 }
1183
DumpMethods(MethodVector methods,int indent)1184 static void DumpMethods(MethodVector methods, int indent)
1185 {
1186 size_t size = methods.size();
1187 for (size_t i = 0; i < size; ++i) {
1188 LogInfo::MapleLogger() << '\n';
1189 PrintIndentation(indent);
1190 MIRSymbol *mFirstSymbol = GlobalTables::GetGsymTable().GetSymbolFromStidx(methods[i].first.Idx());
1191 DEBUG_ASSERT(mFirstSymbol != nullptr, "null ptr check");
1192 LogInfo::MapleLogger() << "&" << mFirstSymbol->GetName();
1193 methods[i].second.second.DumpAttributes();
1194 LogInfo::MapleLogger() << " (";
1195 auto *funcType =
1196 static_cast<MIRFuncType *>(GlobalTables::GetTypeTable().GetTypeFromTyIdx(methods[i].second.first));
1197 size_t parmListSize = funcType->GetParamTypeList().size();
1198 for (size_t j = 0; j < parmListSize; ++j) {
1199 GlobalTables::GetTypeTable().GetTypeFromTyIdx(funcType->GetNthParamType(j))->Dump(indent + 1);
1200 if (j != parmListSize - 1) {
1201 LogInfo::MapleLogger() << ",";
1202 }
1203 }
1204 if (funcType->IsVarargs()) {
1205 LogInfo::MapleLogger() << ", ...";
1206 }
1207 LogInfo::MapleLogger() << ") ";
1208 GlobalTables::GetTypeTable().GetTypeFromTyIdx(funcType->GetRetTyIdx())->Dump(indent + 1);
1209 if (i != size - 1) {
1210 LogInfo::MapleLogger() << ",";
1211 }
1212 }
1213 }
1214
DumpConstructorsAsCxx(MethodVector methods,int indent)1215 static void DumpConstructorsAsCxx(MethodVector methods, int indent)
1216 {
1217 unsigned int i = 0;
1218 for (auto &m : methods) {
1219 FuncAttrs &fa = m.second.second;
1220 if (!fa.GetAttr(FUNCATTR_constructor) || !fa.GetAttr(FUNCATTR_public)) {
1221 continue;
1222 }
1223 auto *funcType = static_cast<MIRFuncType *>(GlobalTables::GetTypeTable().GetTypeFromTyIdx(m.second.first));
1224 PrintIndentation(indent);
1225 MIRSymbol *mFirstSymbol = GlobalTables::GetGsymTable().GetSymbolFromStidx(m.first.Idx());
1226 DEBUG_ASSERT(mFirstSymbol != nullptr, "null ptr check");
1227 LogInfo::MapleLogger() << "/* &" << mFirstSymbol->GetName();
1228 fa.DumpAttributes();
1229 LogInfo::MapleLogger() << " (";
1230 unsigned int j = 0;
1231 size_t paramTypeListSize = funcType->GetParamTypeList().size();
1232 for (auto &p : funcType->GetParamTypeList()) {
1233 GlobalTables::GetTypeTable().GetTypeFromTyIdx(p)->Dump(indent + 1);
1234 CHECK_FATAL(paramTypeListSize > 0, "must not be zero");
1235 if (j != paramTypeListSize - 1) {
1236 LogInfo::MapleLogger() << ", ";
1237 }
1238 ++j;
1239 }
1240 if (funcType->IsVarargs()) {
1241 LogInfo::MapleLogger() << ", ...";
1242 }
1243 LogInfo::MapleLogger() << ") ";
1244 GlobalTables::GetTypeTable().GetTypeFromTyIdx(funcType->GetRetTyIdx())->Dump(indent + 1);
1245 LogInfo::MapleLogger() << " */" << '\n';
1246 PrintIndentation(indent);
1247 LogInfo::MapleLogger() << "/* ";
1248 LogInfo::MapleLogger() << namemangler::DecodeName(mFirstSymbol->GetName());
1249 LogInfo::MapleLogger() << " */" << '\n';
1250 PrintIndentation(indent);
1251 LogInfo::MapleLogger() << "extern \"C\" ";
1252 // return type
1253 GlobalTables::GetTypeTable().GetTypeFromTyIdx(funcType->GetRetTyIdx())->DumpAsCxx(0);
1254 LogInfo::MapleLogger() << " " << mFirstSymbol->GetName() << "( ";
1255 j = 0;
1256 for (auto &p : funcType->GetParamTypeList()) {
1257 GlobalTables::GetTypeTable().GetTypeFromTyIdx(p)->DumpAsCxx(indent + 1);
1258 DEBUG_ASSERT(paramTypeListSize > 0, "paramTypeListSize should not be zero");
1259 if (j != paramTypeListSize - 1) {
1260 LogInfo::MapleLogger() << ", ";
1261 }
1262 ++j;
1263 }
1264 if (funcType->IsVarargs()) {
1265 LogInfo::MapleLogger() << ", ...";
1266 }
1267 LogInfo::MapleLogger() << ")";
1268 DEBUG_ASSERT(methods.size() > 0, "methods.size() should not be zero");
1269 if (methods.size() - 1 != i++) {
1270 LogInfo::MapleLogger() << ";" << '\n';
1271 }
1272 }
1273 }
1274
DumpInterfaces(std::vector<TyIdx> interfaces,int indent)1275 static void DumpInterfaces(std::vector<TyIdx> interfaces, int indent)
1276 {
1277 size_t size = interfaces.size();
1278 for (size_t i = 0; i < size; ++i) {
1279 LogInfo::MapleLogger() << '\n';
1280 PrintIndentation(indent);
1281 GStrIdx stridx = GlobalTables::GetTypeTable().GetTypeFromTyIdx(interfaces[i])->GetNameStrIdx();
1282 LogInfo::MapleLogger() << "$" << GlobalTables::GetStrTable().GetStringFromStrIdx(stridx);
1283 if (i != size - 1) {
1284 LogInfo::MapleLogger() << ",";
1285 }
1286 }
1287 }
1288
GetSize() const1289 size_t MIRStructType::GetSize() const
1290 {
1291 if (size != kInvalidSize) {
1292 return size;
1293 }
1294 if (typeKind == kTypeUnion) {
1295 if (fields.size() == 0) {
1296 return isCPlusPlus ? 1 : 0;
1297 }
1298 size = 0;
1299 for (size_t i = 0; i < fields.size(); ++i) {
1300 TyIdxFieldAttrPair tfap = GetTyidxFieldAttrPair(i);
1301 MIRType *fieldType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tfap.first);
1302 size_t fldSize = RoundUp(fieldType->GetSize(), tfap.second.GetAlign());
1303 if (size < fldSize) {
1304 size = fldSize;
1305 }
1306 }
1307 return size;
1308 }
1309 // since there may be bitfields, perform a layout process for the fields
1310 size_t byteOfst = 0;
1311 size_t bitOfst = 0;
1312 constexpr uint32 shiftNum = 3;
1313 for (size_t i = 0; i < fields.size(); ++i) {
1314 TyIdxFieldAttrPair tfap = GetTyidxFieldAttrPair(i);
1315 MIRType *fieldType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tfap.first);
1316 if (fieldType->GetKind() != kTypeBitField) {
1317 if (byteOfst * k8BitSize < bitOfst) {
1318 byteOfst = (bitOfst >> shiftNum) + 1;
1319 }
1320 byteOfst = RoundUp(byteOfst, std::max(fieldType->GetAlign(), tfap.second.GetAlign()));
1321 byteOfst += fieldType->GetSize();
1322 bitOfst = byteOfst * k8BitSize;
1323 } else {
1324 MIRBitFieldType *bitfType = static_cast<MIRBitFieldType *>(fieldType);
1325 if (bitfType->GetFieldSize() == 0) { // special case, for aligning purpose
1326 bitOfst = RoundUp(bitOfst, GetPrimTypeBitSize(bitfType->GetPrimType()));
1327 byteOfst = bitOfst >> shiftNum;
1328 } else {
1329 DEBUG_ASSERT(bitfType->GetFieldSize() > 0, "bitfType->GetFieldSize() should not be zero");
1330 CHECK_FATAL((bitOfst <= UINT32_MAX - bitfType->GetFieldSize()), "must not be zero");
1331 if (RoundDown(bitOfst + bitfType->GetFieldSize() - 1, GetPrimTypeBitSize(bitfType->GetPrimType())) !=
1332 RoundDown(bitOfst, GetPrimTypeBitSize(bitfType->GetPrimType()))) {
1333 bitOfst = RoundUp(bitOfst, GetPrimTypeBitSize(bitfType->GetPrimType()));
1334 byteOfst = bitOfst >> shiftNum;
1335 }
1336 bitOfst += bitfType->GetFieldSize();
1337 byteOfst = bitOfst >> shiftNum;
1338 }
1339 }
1340 }
1341 if ((byteOfst << k8BitShift) < bitOfst) {
1342 byteOfst = (bitOfst >> shiftNum) + 1;
1343 }
1344 byteOfst = RoundUp(byteOfst, GetAlign());
1345 if (byteOfst == 0 && isCPlusPlus) {
1346 size = 1;
1347 return 1; // empty struct in C++ has size 1
1348 }
1349 size = byteOfst;
1350 return size;
1351 }
1352
GetAlign() const1353 uint32 MIRStructType::GetAlign() const
1354 {
1355 return GetAlignAux(false);
1356 }
1357
1358 // return original align for typedef struct
GetTypedefOriginalAlign() const1359 uint32 MIRStructType::GetTypedefOriginalAlign() const
1360 {
1361 return GetAlignAux(true);
1362 }
1363
GetAlignAux(bool toGetOriginal) const1364 uint32 MIRStructType::GetAlignAux(bool toGetOriginal) const
1365 {
1366 if (fields.size() == 0) {
1367 return std::max(1u, GetTypeAttrs().GetAlign());
1368 }
1369 uint32 maxAlign = 1;
1370 uint32 maxZeroBitFieldAlign = 1;
1371 auto structPack = GetTypeAttrs().GetPack();
1372 auto packed = GetTypeAttrs().IsPacked();
1373 for (size_t i = 0; i < fields.size(); ++i) {
1374 TyIdxFieldAttrPair tfap = GetTyidxFieldAttrPair(i);
1375 MIRType *fieldType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tfap.first);
1376 auto originAlign =
1377 fieldType->GetKind() != kTypeBitField ? fieldType->GetAlign() : GetPrimTypeSize(fieldType->GetPrimType());
1378 uint32 fieldAlign =
1379 (packed || tfap.second.IsPacked()) ? static_cast<uint32>(1U) : std::min(originAlign, structPack);
1380 fieldAlign = tfap.second.HasAligned() ? std::max(fieldAlign, tfap.second.GetAlign()) : fieldAlign;
1381 fieldAlign = GetTypeAttrs().HasPack() ? std::min(GetTypeAttrs().GetPack(), fieldAlign) : fieldAlign;
1382 CHECK_FATAL(fieldAlign != 0, "expect fieldAlign not equal 0");
1383 maxAlign = std::max(maxAlign, fieldAlign);
1384 if (fieldType->IsMIRBitFieldType() && static_cast<MIRBitFieldType *>(fieldType)->GetFieldSize() == 0) {
1385 maxZeroBitFieldAlign = std::max(maxZeroBitFieldAlign, GetPrimTypeSize(fieldType->GetPrimType()));
1386 }
1387 }
1388 uint32 attrAlign = GetTypeAttrs().GetAlign();
1389 if (GetTypeAttrs().IsTypedef()) {
1390 // when calculating typedef's own size, we need to use its original align
1391 if (toGetOriginal) {
1392 // anonymous struct type def
1393 if (GetTypeAttrs().GetOriginType() == nullptr) {
1394 attrAlign = GetTypeAttrs().GetAlign();
1395 // unanonymous struct type def
1396 } else {
1397 attrAlign = static_cast<MIRStructType *>(GetTypeAttrs().GetOriginType())->GetTypeAttrs().GetAlign();
1398 }
1399 // when calculating typedef struct is a field of another struct, we need to use its typealign.
1400 } else {
1401 attrAlign = GetTypeAttrs().GetTypeAlign();
1402 }
1403 }
1404 if (HasZeroWidthBitField()) {
1405 return std::max(attrAlign, std::max(maxZeroBitFieldAlign, maxAlign));
1406 }
1407 return std::max(attrAlign, maxAlign);
1408 }
1409
1410 // Used to determine date alignment in ABI.
1411 // In fact, this alignment of type should be in the context of language/ABI, not MIRType.
1412 // For simplicity, we implement it in MIRType now.
1413 // Need check why "packed" is within the context of ABI.
GetUnadjustedAlign() const1414 uint32 MIRStructType::GetUnadjustedAlign() const
1415 {
1416 if (fields.size() == 0) {
1417 return 1u;
1418 }
1419 uint32 maxAlign = 1;
1420 uint32 maxZeroBitFieldAlign = 1;
1421 auto structPack = GetTypeAttrs().GetPack();
1422 auto packed = GetTypeAttrs().IsPacked();
1423 for (size_t i = 0; i < fields.size(); ++i) {
1424 TyIdxFieldAttrPair tfap = GetTyidxFieldAttrPair(i);
1425 MIRType *fieldType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tfap.first);
1426 auto originAlign =
1427 fieldType->GetKind() != kTypeBitField ? fieldType->GetAlign() : GetPrimTypeSize(fieldType->GetPrimType());
1428 uint32 fieldAlign =
1429 (packed || tfap.second.IsPacked()) ? static_cast<uint32>(1U) : std::min(originAlign, structPack);
1430 fieldAlign = tfap.second.HasAligned() ? std::max(fieldAlign, tfap.second.GetAlign()) : fieldAlign;
1431 fieldAlign = GetTypeAttrs().HasPack() ? std::min(GetTypeAttrs().GetPack(), fieldAlign) : fieldAlign;
1432 CHECK_FATAL(fieldAlign != 0, "expect fieldAlign not equal 0");
1433 maxAlign = std::max(maxAlign, fieldAlign);
1434 if (fieldType->IsMIRBitFieldType() && static_cast<MIRBitFieldType *>(fieldType)->GetFieldSize() == 0) {
1435 maxZeroBitFieldAlign = std::max(maxZeroBitFieldAlign, GetPrimTypeSize(fieldType->GetPrimType()));
1436 }
1437 }
1438 if (HasZeroWidthBitField()) {
1439 return std::max(maxZeroBitFieldAlign, maxAlign);
1440 }
1441 return maxAlign;
1442 }
1443
DumpFieldsAndMethods(int indent,bool hasMethod) const1444 void MIRStructType::DumpFieldsAndMethods(int indent, bool hasMethod) const
1445 {
1446 DumpFields(fields, indent);
1447 bool hasField = !fields.empty();
1448 bool hasStaticField = !staticFields.empty();
1449 if (hasField && hasStaticField) {
1450 LogInfo::MapleLogger() << ",";
1451 }
1452 DumpFields(staticFields, indent, true);
1453 bool hasFieldOrStaticField = hasField || hasStaticField;
1454 bool hasParentField = !parentFields.empty();
1455 if (hasFieldOrStaticField && hasParentField) {
1456 LogInfo::MapleLogger() << ",";
1457 }
1458 DumpFields(parentFields, indent, true);
1459 if ((hasFieldOrStaticField || hasParentField) && hasMethod) {
1460 LogInfo::MapleLogger() << ",";
1461 }
1462 DumpMethods(methods, indent);
1463 }
1464
Dump(int indent,bool dontUseName) const1465 void MIRStructType::Dump(int indent, bool dontUseName) const
1466 {
1467 if (!dontUseName && CheckAndDumpTypeName(nameStrIdx, nameIsLocal)) {
1468 return;
1469 }
1470 LogInfo::MapleLogger() << ((typeKind == kTypeStruct) ? "<struct"
1471 : ((typeKind == kTypeUnion) ? "<union" : "<structincomplete"));
1472 typeAttrs.DumpAttributes();
1473 LogInfo::MapleLogger() << " {";
1474 DumpFieldsAndMethods(indent, !methods.empty());
1475 LogInfo::MapleLogger() << "}>";
1476 }
1477
GetInfo(GStrIdx strIdx) const1478 uint32 MIRClassType::GetInfo(GStrIdx strIdx) const
1479 {
1480 return GetInfoFromStrIdx(info, strIdx);
1481 }
1482
1483 // return class id or superclass id accroding to input string
GetInfo(const std::string & infoStr) const1484 uint32 MIRClassType::GetInfo(const std::string &infoStr) const
1485 {
1486 GStrIdx strIdx = GlobalTables::GetStrTable().GetStrIdxFromName(infoStr);
1487 return GetInfo(strIdx);
1488 }
1489
IsFinal() const1490 bool MIRClassType::IsFinal() const
1491 {
1492 if (!IsStructType()) {
1493 return false;
1494 }
1495 uint32 attrStrIdx = GetInfo(GlobalTables::GetStrTable().GetOrCreateStrIdxFromName("INFO_attribute_string"));
1496 CHECK(attrStrIdx < GlobalTables::GetStrTable().StringTableSize(), "out of range of vector");
1497 const std::string &kAttrString = GlobalTables::GetStrTable().GetStringFromStrIdx(GStrIdx(attrStrIdx));
1498 return kAttrString.find(" final ") != std::string::npos;
1499 }
1500
IsAbstract() const1501 bool MIRClassType::IsAbstract() const
1502 {
1503 uint32 attrStrIdx = GetInfo(GlobalTables::GetStrTable().GetOrCreateStrIdxFromName("INFO_attribute_string"));
1504 CHECK(attrStrIdx < GlobalTables::GetStrTable().StringTableSize(), "out of range of vector");
1505 const std::string &kAttrString = GlobalTables::GetStrTable().GetStringFromStrIdx(GStrIdx(attrStrIdx));
1506 return kAttrString.find(" abstract ") != std::string::npos;
1507 }
1508
IsInner() const1509 bool MIRClassType::IsInner() const
1510 {
1511 const std::string &name = GetName();
1512 return name.find("_24") != std::string::npos;
1513 }
1514
DumpInfoPragmaStaticValue(const std::vector<MIRInfoPair> & info,const std::vector<MIRPragma * > & pragmaVec,const MIREncodedArray & staticValue,int indent,bool hasFieldMethodOrInterface)1515 static void DumpInfoPragmaStaticValue(const std::vector<MIRInfoPair> &info, const std::vector<MIRPragma *> &pragmaVec,
1516 const MIREncodedArray &staticValue, int indent, bool hasFieldMethodOrInterface)
1517 {
1518 bool hasPragma = pragmaVec.size();
1519 bool hasStaticValue = staticValue.size();
1520 if (!info.empty() && (hasPragma || hasStaticValue || hasFieldMethodOrInterface)) {
1521 LogInfo::MapleLogger() << ",";
1522 }
1523 size_t size = pragmaVec.size();
1524 for (size_t i = 0; i < size; ++i) {
1525 pragmaVec[i]->Dump(indent);
1526 if (i != size - 1) {
1527 LogInfo::MapleLogger() << ",";
1528 }
1529 }
1530 if (hasPragma && (hasStaticValue || hasFieldMethodOrInterface)) {
1531 LogInfo::MapleLogger() << ",";
1532 }
1533 DumpStaticValue(staticValue, indent);
1534 if (hasStaticValue && hasFieldMethodOrInterface) {
1535 LogInfo::MapleLogger() << ",";
1536 }
1537 }
1538
Dump(int indent,bool dontUseName) const1539 void MIRClassType::Dump(int indent, bool dontUseName) const
1540 {
1541 if (!dontUseName && CheckAndDumpTypeName(nameStrIdx, nameIsLocal)) {
1542 return;
1543 }
1544 LogInfo::MapleLogger() << ((typeKind == kTypeClass) ? "<class " : "<classincomplete ");
1545 if (parentTyIdx != 0u) {
1546 GlobalTables::GetTypeTable().GetTypeFromTyIdx(parentTyIdx)->Dump(indent + 1);
1547 LogInfo::MapleLogger() << " ";
1548 }
1549 LogInfo::MapleLogger() << "{";
1550 DumpClassOrInterfaceInfo(*this, indent);
1551 bool hasFieldMethodOrInterface = !(fields.empty() && parentFields.empty() && staticFields.empty() &&
1552 methods.empty() && interfacesImplemented.empty());
1553 DumpInfoPragmaStaticValue(info, pragmaVec, staticValue, indent, hasFieldMethodOrInterface);
1554
1555 bool hasMethod = !methods.empty();
1556 bool hasImplementedInterface = !interfacesImplemented.empty();
1557 DumpFieldsAndMethods(indent, hasMethod || hasImplementedInterface);
1558 if (hasMethod && hasImplementedInterface) {
1559 LogInfo::MapleLogger() << ",";
1560 }
1561 DumpInterfaces(interfacesImplemented, indent);
1562 LogInfo::MapleLogger() << "}>";
1563 }
1564
DumpAsCxx(int indent) const1565 void MIRClassType::DumpAsCxx(int indent) const
1566 {
1567 LogInfo::MapleLogger() << "{\n";
1568 DumpFieldsAsCxx(fields, indent);
1569 LogInfo::MapleLogger() << "};\n";
1570 DumpConstructorsAsCxx(methods, 0);
1571 }
1572
Dump(int indent,bool dontUseName) const1573 void MIRInterfaceType::Dump(int indent, bool dontUseName) const
1574 {
1575 if (!dontUseName && CheckAndDumpTypeName(nameStrIdx, nameIsLocal)) {
1576 return;
1577 }
1578 LogInfo::MapleLogger() << ((typeKind == kTypeInterface) ? "<interface " : "<interfaceincomplete ");
1579 for (TyIdx idx : parentsTyIdx) {
1580 GlobalTables::GetTypeTable().GetTypeFromTyIdx(idx)->Dump(0);
1581 LogInfo::MapleLogger() << " ";
1582 }
1583 LogInfo::MapleLogger() << " {";
1584 DumpClassOrInterfaceInfo(*this, indent);
1585 bool hasFieldOrMethod = !(fields.empty() && staticFields.empty() && parentFields.empty() && methods.empty());
1586 DumpInfoPragmaStaticValue(info, pragmaVec, staticValue, indent, hasFieldOrMethod);
1587 DumpFieldsAndMethods(indent, !methods.empty());
1588 LogInfo::MapleLogger() << "}>";
1589 }
1590
Dump(int indent,bool dontUseName) const1591 void MIRTypeByName::Dump(int indent, bool dontUseName) const
1592 {
1593 const std::string &name = GlobalTables::GetStrTable().GetStringFromStrIdx(nameStrIdx);
1594 LogInfo::MapleLogger() << (nameIsLocal ? "<%" : "<$") << name << ">";
1595 }
1596
Dump(int indent,bool dontUseName) const1597 void MIRTypeParam::Dump(int indent, bool dontUseName) const
1598 {
1599 const std::string &name = GlobalTables::GetStrTable().GetStringFromStrIdx(nameStrIdx);
1600 LogInfo::MapleLogger() << "<!" << name << ">";
1601 }
1602
Dump(int indent,bool dontUseName) const1603 void MIRInstantVectorType::Dump(int indent, bool dontUseName) const
1604 {
1605 LogInfo::MapleLogger() << "{";
1606 for (size_t i = 0; i < instantVec.size(); ++i) {
1607 TypePair typePair = instantVec[i];
1608 if (i != 0) {
1609 LogInfo::MapleLogger() << ", ";
1610 }
1611 MIRType *typeParmType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(typePair.first);
1612 const std::string &name = GlobalTables::GetStrTable().GetStringFromStrIdx(typeParmType->GetNameStrIdx());
1613 LogInfo::MapleLogger() << "!" << name << "=";
1614 MIRType *realty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(typePair.second);
1615 realty->Dump(0);
1616 }
1617 LogInfo::MapleLogger() << "}";
1618 }
1619
Dump(int indent,bool dontUseName) const1620 void MIRGenericInstantType::Dump(int indent, bool dontUseName) const
1621 {
1622 LogInfo::MapleLogger() << "<";
1623 const MIRType *genericType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(genericTyIdx);
1624 DumpTypeName(genericType->GetNameStrIdx(), genericType->IsNameIsLocal());
1625 MIRInstantVectorType::Dump(indent, dontUseName);
1626 LogInfo::MapleLogger() << ">";
1627 }
1628
EqualTo(const MIRType & mirType) const1629 bool MIRType::EqualTo(const MIRType &mirType) const
1630 {
1631 return typeKind == mirType.typeKind && primType == mirType.primType;
1632 }
1633
EqualTo(const MIRType & type) const1634 bool MIRPtrType::EqualTo(const MIRType &type) const
1635 {
1636 if (typeKind != type.GetKind() || GetPrimType() != type.GetPrimType()) {
1637 return false;
1638 }
1639 const auto &pType = static_cast<const MIRPtrType &>(type);
1640 return pointedTyIdx == pType.GetPointedTyIdx() && typeAttrs == pType.GetTypeAttrs();
1641 }
1642
EqualTo(const MIRType & type) const1643 bool MIRArrayType::EqualTo(const MIRType &type) const
1644 {
1645 if (type.GetKind() != typeKind) {
1646 return false;
1647 }
1648 const auto &pType = static_cast<const MIRArrayType &>(type);
1649 if (dim != pType.GetDim() || eTyIdx != pType.GetElemTyIdx() || typeAttrs != pType.GetTypeAttrs()) {
1650 return false;
1651 }
1652 for (size_t i = 0; i < dim; ++i) {
1653 if (GetSizeArrayItem(i) != pType.GetSizeArrayItem(i)) {
1654 return false;
1655 }
1656 }
1657 return true;
1658 }
1659
GetElemType() const1660 MIRType *MIRArrayType::GetElemType() const
1661 {
1662 return GlobalTables::GetTypeTable().GetTypeFromTyIdx(eTyIdx);
1663 }
1664
GetMplTypeName() const1665 std::string MIRArrayType::GetMplTypeName() const
1666 {
1667 std::stringstream ss;
1668 ss << "<[] ";
1669 MIRType *elemType = GetElemType();
1670 ss << elemType->GetMplTypeName();
1671 ss << ">";
1672 return ss.str();
1673 }
1674
HasFields() const1675 bool MIRArrayType::HasFields() const
1676 {
1677 MIRType *elemType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(eTyIdx);
1678 return elemType->HasFields();
1679 }
1680
NumberOfFieldIDs() const1681 uint32 MIRArrayType::NumberOfFieldIDs() const
1682 {
1683 if (fieldsNum != kInvalidFieldNum) {
1684 return fieldsNum;
1685 }
1686 MIRType *elemType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(eTyIdx);
1687 fieldsNum = elemType->NumberOfFieldIDs();
1688 return fieldsNum;
1689 }
1690
EmbeddedStructType()1691 MIRStructType *MIRArrayType::EmbeddedStructType()
1692 {
1693 MIRType *elemType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(eTyIdx);
1694 return elemType->EmbeddedStructType();
1695 }
1696
GetBitOffsetFromArrayAddress(std::vector<int64> & indexArray)1697 int64 MIRArrayType::GetBitOffsetFromArrayAddress(std::vector<int64> &indexArray)
1698 {
1699 // for cases that num of dimension-operand is less than array's dimension
1700 // e.g. array 1 ptr <* <[d1][d2][d3] type>> (array_base_addr, dim1_opnd)
1701 // array's dimension is 3, and dimension-opnd's num is 1;
1702 if (indexArray.size() < dim) {
1703 indexArray.insert(indexArray.end(), dim - indexArray.size(), 0);
1704 }
1705 if (GetElemType()->GetKind() == kTypeArray) {
1706 // for cases that array's dimension is less than num of dimension-opnd
1707 // e.g array 1 ptr <* <[d1] <[d2] type>>> (array_base_addr, dim1_opnd, dim2_opnd)
1708 // array's dimension is 1 (its element type is <[d2] type>), and dimension-opnd-num is 2
1709 CHECK_FATAL(indexArray.size() >= dim, "dimension mismatch!");
1710 } else {
1711 CHECK_FATAL(indexArray.size() == dim, "dimension mismatch!");
1712 }
1713 int64 sum = 0; // element numbers before the specified element
1714 uint32 numberOfElemInLowerDim = 1;
1715 for (uint32 id = 1; id <= dim; ++id) {
1716 sum += indexArray[dim - id] * static_cast<int64>(numberOfElemInLowerDim);
1717 numberOfElemInLowerDim *= sizeArray[dim - id];
1718 }
1719 size_t elemsize = GetElemType()->GetSize();
1720 if (elemsize == 0 || sum == 0) {
1721 return 0;
1722 }
1723 elemsize = RoundUp(elemsize, typeAttrs.GetAlign());
1724 constexpr int64 bitsPerByte = 8;
1725 int64 offset = static_cast<int64>(static_cast<uint64>(sum) * elemsize * static_cast<uint64>(bitsPerByte));
1726 if (GetElemType()->GetKind() == kTypeArray && indexArray.size() > dim) {
1727 std::vector<int64> subIndexArray(indexArray.begin() + dim, indexArray.end());
1728 offset += static_cast<MIRArrayType *>(GetElemType())->GetBitOffsetFromArrayAddress(subIndexArray);
1729 }
1730 return offset;
1731 }
1732
ElemNumber() const1733 size_t MIRArrayType::ElemNumber() const
1734 {
1735 size_t elemNum = 1;
1736 for (uint16 id = 0; id < dim; ++id) {
1737 elemNum *= sizeArray[id];
1738 }
1739
1740 auto elemType = GetElemType();
1741 if (elemType->GetKind() == kTypeArray) {
1742 elemNum *= static_cast<MIRArrayType *>(elemType)->ElemNumber();
1743 }
1744 return elemNum;
1745 }
1746
GetElemType() const1747 MIRType *MIRFarrayType::GetElemType() const
1748 {
1749 return GlobalTables::GetTypeTable().GetTypeFromTyIdx(elemTyIdx);
1750 }
1751
EqualTo(const MIRType & type) const1752 bool MIRFarrayType::EqualTo(const MIRType &type) const
1753 {
1754 if (type.GetKind() != typeKind) {
1755 return false;
1756 }
1757 const auto &pType = static_cast<const MIRFarrayType &>(type);
1758 return elemTyIdx == pType.GetElemTyIdx();
1759 }
1760
GetMplTypeName() const1761 std::string MIRFarrayType::GetMplTypeName() const
1762 {
1763 std::stringstream ss;
1764 ss << "<[] ";
1765 MIRType *elemType = GetElemType();
1766 ss << elemType->GetMplTypeName();
1767 ss << ">";
1768 return ss.str();
1769 }
1770
HasFields() const1771 bool MIRFarrayType::HasFields() const
1772 {
1773 MIRType *elemType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(elemTyIdx);
1774 return elemType->HasFields();
1775 }
1776
NumberOfFieldIDs() const1777 uint32 MIRFarrayType::NumberOfFieldIDs() const
1778 {
1779 if (fieldsNum != kInvalidFieldNum) {
1780 return fieldsNum;
1781 }
1782 MIRType *elemType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(elemTyIdx);
1783 fieldsNum = elemType->NumberOfFieldIDs();
1784 return fieldsNum;
1785 }
1786
EmbeddedStructType()1787 MIRStructType *MIRFarrayType::EmbeddedStructType()
1788 {
1789 MIRType *elemType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(elemTyIdx);
1790 return elemType->EmbeddedStructType();
1791 }
1792
GetBitOffsetFromArrayAddress(int64 arrayIndex)1793 int64 MIRFarrayType::GetBitOffsetFromArrayAddress(int64 arrayIndex)
1794 {
1795 size_t elemsize = GetElemType()->GetSize();
1796 if (elemsize == 0 || arrayIndex == 0) {
1797 return 0;
1798 }
1799 uint32 elemAlign = GetElemType()->GetAlign();
1800 elemsize = RoundUp(elemsize, elemAlign);
1801 constexpr int64 bitsPerByte = 8;
1802 return arrayIndex * static_cast<int64>(elemsize) * bitsPerByte;
1803 }
1804
EqualTo(const MIRType & type) const1805 bool MIRFuncType::EqualTo(const MIRType &type) const
1806 {
1807 if (type.GetKind() != typeKind) {
1808 return false;
1809 }
1810 const auto &pType = static_cast<const MIRFuncType &>(type);
1811 return (pType.retTyIdx == retTyIdx && pType.paramTypeList == paramTypeList && pType.funcAttrs == funcAttrs &&
1812 pType.paramAttrsList == paramAttrsList && pType.retAttrs == retAttrs);
1813 }
1814
TypeCompatible(TyIdx typeIdx1,TyIdx typeIdx2)1815 static bool TypeCompatible(TyIdx typeIdx1, TyIdx typeIdx2)
1816 {
1817 if (typeIdx1 == typeIdx2) {
1818 return true;
1819 }
1820 MIRType *type1 = GlobalTables::GetTypeTable().GetTypeFromTyIdx(typeIdx1);
1821 MIRType *type2 = GlobalTables::GetTypeTable().GetTypeFromTyIdx(typeIdx2);
1822 if (type1 == nullptr || type2 == nullptr) {
1823 // this means we saw the use of this symbol before def.
1824 return false;
1825 }
1826 while (type1->IsMIRPtrType() || type1->IsMIRArrayType()) {
1827 if (type1->IsMIRPtrType()) {
1828 if (!type2->IsMIRPtrType()) {
1829 return false;
1830 }
1831 type1 = static_cast<MIRPtrType *>(type1)->GetPointedType();
1832 type2 = static_cast<MIRPtrType *>(type2)->GetPointedType();
1833 } else {
1834 if (!type2->IsMIRArrayType()) {
1835 return false;
1836 }
1837 type1 = static_cast<MIRArrayType *>(type1)->GetElemType();
1838 type2 = static_cast<MIRArrayType *>(type2)->GetElemType();
1839 }
1840 }
1841 if (type1 == type2) {
1842 return true;
1843 }
1844 if (type1->GetPrimType() == PTY_void || type2->GetPrimType() == PTY_void) {
1845 return true;
1846 }
1847 if (type1->IsIncomplete() || type2->IsIncomplete()) {
1848 return true;
1849 }
1850 return false;
1851 }
1852
CompatibleWith(const MIRType & type) const1853 bool MIRFuncType::CompatibleWith(const MIRType &type) const
1854 {
1855 if (type.GetKind() != typeKind) {
1856 return false;
1857 }
1858 const auto &pType = static_cast<const MIRFuncType &>(type);
1859 if (!TypeCompatible(pType.retTyIdx, retTyIdx)) {
1860 return false;
1861 }
1862 if (pType.paramTypeList.size() != paramTypeList.size()) {
1863 return false;
1864 }
1865 for (size_t i = 0; i < paramTypeList.size(); i++) {
1866 if (!TypeCompatible(pType.GetNthParamType(i), GetNthParamType(i))) {
1867 return false;
1868 }
1869 }
1870 return true;
1871 }
1872
EqualTo(const MIRType & type) const1873 bool MIRBitFieldType::EqualTo(const MIRType &type) const
1874 {
1875 if (type.GetKind() != typeKind || type.GetPrimType() != primType) {
1876 return false;
1877 }
1878 const auto &pType = static_cast<const MIRBitFieldType &>(type);
1879 return pType.fieldSize == fieldSize;
1880 }
1881
EqualTo(const MIRType & type) const1882 bool MIRStructType::EqualTo(const MIRType &type) const
1883 {
1884 if (type.GetKind() != typeKind) {
1885 return false;
1886 }
1887 if (type.GetNameStrIdx() != nameStrIdx) {
1888 return false;
1889 }
1890
1891 DEBUG_ASSERT(type.IsStructType(), "p is null in MIRStructType::EqualTo");
1892 const MIRStructType *p = static_cast<const MIRStructType *>(&type);
1893 if (typeAttrs != p->typeAttrs) {
1894 return false;
1895 }
1896 if (fields != p->fields) {
1897 return false;
1898 }
1899 if (staticFields != p->staticFields) {
1900 return false;
1901 }
1902 if (parentFields != p->parentFields) {
1903 return false;
1904 }
1905 if (methods != p->methods) {
1906 return false;
1907 }
1908 return true;
1909 }
1910
GetCompactMplTypeName() const1911 std::string MIRStructType::GetCompactMplTypeName() const
1912 {
1913 return GlobalTables::GetStrTable().GetStringFromStrIdx(nameStrIdx);
1914 }
1915
GetElemType(uint32 n) const1916 MIRType *MIRStructType::GetElemType(uint32 n) const
1917 {
1918 return GlobalTables::GetTypeTable().GetTypeFromTyIdx(GetElemTyIdx(n));
1919 }
1920
GetFieldType(FieldID fieldID)1921 MIRType *MIRStructType::GetFieldType(FieldID fieldID)
1922 {
1923 if (fieldID == 0) {
1924 return this;
1925 }
1926 const FieldPair &fieldPair = TraverseToFieldRef(fieldID);
1927 return GlobalTables::GetTypeTable().GetTypeFromTyIdx(fieldPair.second.first);
1928 }
1929
IsLocal() const1930 bool MIRStructType::IsLocal() const
1931 {
1932 return GlobalTables::GetGsymTable().GetStIdxFromStrIdx(nameStrIdx).Idx() != 0;
1933 }
1934
GetMplTypeName() const1935 std::string MIRStructType::GetMplTypeName() const
1936 {
1937 std::stringstream ss;
1938 ss << "<$";
1939 ss << GlobalTables::GetStrTable().GetStringFromStrIdx(nameStrIdx);
1940 ss << ">";
1941 return ss.str();
1942 }
1943
EqualTo(const MIRType & type) const1944 bool MIRClassType::EqualTo(const MIRType &type) const
1945 {
1946 if (type.GetKind() != typeKind) {
1947 return false;
1948 }
1949 bool structeq = MIRStructType::EqualTo(type);
1950 if (!structeq) {
1951 return false;
1952 }
1953
1954 const MIRClassType &classty = static_cast<const MIRClassType &>(type);
1955 // classes have parent except empty/thirdparty classes
1956 if (parentTyIdx != classty.parentTyIdx) {
1957 return false;
1958 }
1959
1960 if (interfacesImplemented != classty.interfacesImplemented) {
1961 return false;
1962 }
1963 if (info != classty.info) {
1964 return false;
1965 }
1966 if (infoIsString != classty.infoIsString) {
1967 return false;
1968 }
1969 return true;
1970 }
1971
EqualTo(const MIRType & type) const1972 bool MIRInterfaceType::EqualTo(const MIRType &type) const
1973 {
1974 if (type.GetKind() != typeKind) {
1975 return false;
1976 }
1977 bool structeq = MIRStructType::EqualTo(type);
1978 if (!structeq) {
1979 return false;
1980 }
1981
1982 const MIRInterfaceType &interfacety = static_cast<const MIRInterfaceType &>(type);
1983 if (parentsTyIdx != interfacety.parentsTyIdx) {
1984 return false;
1985 }
1986 if (info != interfacety.info) {
1987 return false;
1988 }
1989 if (infoIsString != interfacety.infoIsString) {
1990 return false;
1991 }
1992 return true;
1993 }
1994
EqualTo(const MIRType & type) const1995 bool MIRTypeByName::EqualTo(const MIRType &type) const
1996 {
1997 return type.GetKind() == typeKind && type.GetNameStrIdx() == nameStrIdx && type.IsNameIsLocal() == nameIsLocal;
1998 }
1999
EqualTo(const MIRType & type) const2000 bool MIRTypeParam::EqualTo(const MIRType &type) const
2001 {
2002 return type.GetKind() == typeKind && type.GetNameStrIdx() == nameStrIdx;
2003 }
2004
EqualTo(const MIRType & type) const2005 bool MIRInstantVectorType::EqualTo(const MIRType &type) const
2006 {
2007 if (type.GetKind() != typeKind) {
2008 return false;
2009 }
2010 const auto &pty = static_cast<const MIRInstantVectorType &>(type);
2011 return (instantVec == pty.GetInstantVec());
2012 }
2013
EqualTo(const MIRType & type) const2014 bool MIRGenericInstantType::EqualTo(const MIRType &type) const
2015 {
2016 if (!MIRInstantVectorType::EqualTo(type)) {
2017 return false;
2018 }
2019 const auto &pType = static_cast<const MIRGenericInstantType &>(type);
2020 return genericTyIdx == pType.GetGenericTyIdx();
2021 }
2022
2023 // in the search, curfieldid is being decremented until it reaches 1
TraverseToFieldRef(FieldID & fieldID) const2024 FieldPair MIRStructType::TraverseToFieldRef(FieldID &fieldID) const
2025 {
2026 if (!fields.size()) {
2027 return FieldPair(GStrIdx(0), TyIdxFieldAttrPair(TyIdx(0), FieldAttrs()));
2028 }
2029
2030 uint32 fieldIdx = 0;
2031 FieldPair curPair = fields[0];
2032 while (fieldID > 1) {
2033 --fieldID;
2034 MIRType *curFieldType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(curPair.second.first);
2035 MIRStructType *subStructTy = curFieldType->EmbeddedStructType();
2036 if (subStructTy != nullptr) {
2037 curPair = subStructTy->TraverseToFieldRef(fieldID);
2038 if (fieldID == 1 && curPair.second.first != TyIdx(0)) {
2039 return curPair;
2040 }
2041 }
2042 ++fieldIdx;
2043 if (fieldIdx == fields.size()) {
2044 return FieldPair(GStrIdx(0), TyIdxFieldAttrPair(TyIdx(0), FieldAttrs()));
2045 }
2046 curPair = fields[fieldIdx];
2047 }
2048 return curPair;
2049 }
2050
TraverseToField(FieldID fieldID) const2051 FieldPair MIRStructType::TraverseToField(FieldID fieldID) const
2052 {
2053 if (fieldID >= 0) {
2054 return TraverseToFieldRef(fieldID);
2055 }
2056 // in parentfields
2057 uint32 parentFieldIdx = static_cast<uint32>(-fieldID);
2058 if (parentFields.empty() || parentFieldIdx > parentFields.size()) {
2059 return {GStrIdx(0), TyIdxFieldAttrPair(TyIdx(0), FieldAttrs())};
2060 }
2061 CHECK_FATAL(parentFieldIdx > 0, "must not be zero");
2062 return parentFields[parentFieldIdx - 1];
2063 }
2064
TraverseToFieldInFields(const FieldVector & fields,const GStrIdx & fieldStrIdx,FieldPair & field)2065 static bool TraverseToFieldInFields(const FieldVector &fields, const GStrIdx &fieldStrIdx, FieldPair &field)
2066 {
2067 for (auto &fp : fields) {
2068 if (fp.first == fieldStrIdx) {
2069 field = fp;
2070 return true;
2071 }
2072 }
2073 return false;
2074 }
2075
TraverseToField(GStrIdx fieldStrIdx) const2076 FieldPair MIRStructType::TraverseToField(GStrIdx fieldStrIdx) const
2077 {
2078 FieldPair fieldPair;
2079 if ((!fields.empty() && TraverseToFieldInFields(fields, fieldStrIdx, fieldPair)) ||
2080 (!staticFields.empty() && TraverseToFieldInFields(staticFields, fieldStrIdx, fieldPair)) ||
2081 TraverseToFieldInFields(parentFields, fieldStrIdx, fieldPair)) {
2082 return fieldPair;
2083 }
2084 return {GStrIdx(0), TyIdxFieldAttrPair(TyIdx(0), FieldAttrs())};
2085 }
2086
HasVolatileFieldInFields(const FieldVector & fieldsOfStruct) const2087 bool MIRStructType::HasVolatileFieldInFields(const FieldVector &fieldsOfStruct) const
2088 {
2089 for (const auto &field : fieldsOfStruct) {
2090 if (field.second.second.GetAttr(FLDATTR_volatile) ||
2091 GlobalTables::GetTypeTable().GetTypeFromTyIdx(field.second.first)->HasVolatileField()) {
2092 hasVolatileField = true;
2093 return true;
2094 }
2095 }
2096 hasVolatileField = false;
2097 return false;
2098 }
2099
2100 // go through all the fields to check if there is volatile attribute set;
HasVolatileField() const2101 bool MIRStructType::HasVolatileField() const
2102 {
2103 if (hasVolatileFieldSet) {
2104 return hasVolatileField;
2105 }
2106 hasVolatileFieldSet = true;
2107 return HasVolatileFieldInFields(fields) || HasVolatileFieldInFields(parentFields);
2108 }
2109
GetBitOffsetFromUnionBaseAddr(FieldID fieldID)2110 int64 MIRStructType::GetBitOffsetFromUnionBaseAddr(FieldID fieldID)
2111 {
2112 CHECK_FATAL(fieldID <= static_cast<FieldID>(NumberOfFieldIDs()),
2113 "GetBitOffsetFromUnionBaseAddr: fieldID too large");
2114 if (fieldID == 0) {
2115 return 0;
2116 }
2117
2118 FieldID curFieldID = 1;
2119 FieldVector fieldPairs = GetFields();
2120 // for unions, bitfields are treated as non-bitfields
2121 for (FieldPair field : fieldPairs) {
2122 TyIdx fieldTyIdx = field.second.first;
2123 MIRType *fieldType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(fieldTyIdx);
2124 if (curFieldID == fieldID) {
2125 // target field id is found
2126 // offset of field in union direcly(i.e. not embedded in other struct) is zero.
2127 return 0;
2128 } else {
2129 MIRStructType *subStructType = fieldType->EmbeddedStructType();
2130 if (subStructType == nullptr) {
2131 // field is not a complex structure, no extra field id in it, just inc and continue to next field
2132 curFieldID++;
2133 } else {
2134 // if target field id is in the embedded structure, we should go into it by recursively call
2135 // otherwise, just add the field-id number of the embedded structure, and continue to next field
2136 if ((curFieldID + static_cast<FieldID>(subStructType->NumberOfFieldIDs())) < fieldID) {
2137 // 1 represents subStructType itself
2138 curFieldID += static_cast<FieldID>(subStructType->NumberOfFieldIDs()) + 1;
2139 } else {
2140 return subStructType->GetBitOffsetFromBaseAddr(fieldID - curFieldID);
2141 }
2142 }
2143 }
2144 }
2145 CHECK_FATAL(false, "GetBitOffsetFromUnionBaseAddr() fails to find field");
2146 return kOffsetUnknown;
2147 }
2148
GetBitOffsetFromStructBaseAddr(FieldID fieldID)2149 int64 MIRStructType::GetBitOffsetFromStructBaseAddr(FieldID fieldID)
2150 {
2151 CHECK_FATAL(fieldID <= static_cast<FieldID>(NumberOfFieldIDs()),
2152 "GetBitOffsetFromUnionBaseAddr: fieldID too large");
2153 if (fieldID == 0) {
2154 return 0;
2155 }
2156
2157 uint64 allocedSize = 0; // space need for all fields before currentField
2158 uint64 allocedBitSize = 0;
2159 FieldID curFieldID = 1;
2160 constexpr uint32 bitsPerByte = 8; // 8 bits per byte
2161 FieldVector fieldPairs = GetFields();
2162 // process the struct fields
2163 // There are 3 possible kinds of field in a MIRStructureType:
2164 // case 1 : bitfield (including zero-width bitfield);
2165 // case 2 : primtive field;
2166 // case 3 : normal (empty/non-empty) structure(struct/union) field;
2167 for (FieldPair field : fieldPairs) {
2168 TyIdx fieldTyIdx = field.second.first;
2169 auto fieldAttr = field.second.second;
2170 MIRType *fieldType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(fieldTyIdx);
2171 uint32 fieldBitSize = static_cast<MIRBitFieldType *>(fieldType)->GetFieldSize();
2172 size_t fieldTypeSize = fieldType->GetSize();
2173 uint32 fieldTypeSizeBits = static_cast<uint32>(fieldTypeSize) * bitsPerByte;
2174 auto originAlign = fieldType->GetAlign();
2175 uint32 fieldAlign = fieldAttr.IsPacked() ? 1 : std::min(GetTypeAttrs().GetPack(), originAlign);
2176 auto fieldAlignBits = fieldAlign * bitsPerByte;
2177 // case 1 : bitfield (including zero-width bitfield);
2178 if (fieldType->GetKind() == kTypeBitField) {
2179 fieldTypeSizeBits = static_cast<uint32>(GetPrimTypeSize(fieldType->GetPrimType())) * bitsPerByte;
2180 // Is this field is crossing the align boundary of its base type?
2181 // for example:
2182 // struct Expamle {
2183 // int32 fld1 : 30
2184 // int32 fld2 : 3; // 30 + 3 > 32(= int32 align), cross the align boundary, start from next int32
2185 // boundary
2186 // }
2187 //
2188 // Is field a zero-width bit field?
2189 // Refer to C99 standard (§6.7.2.1) :
2190 // > As a special case, a bit-field structure member with a width of 0 indicates that no further
2191 // > bit-field is to be packed into the unit in which the previous bit-field, if any, was placed.
2192 //
2193 // We know that A zero-width bit field can cause the next field to be aligned on the next container
2194 // boundary where the container is the same size as the underlying type of the bit field.
2195 // for example:
2196 // struct Example {
2197 // int32 fld1 : 5
2198 // int32 : 0 // force the next field to be aligned on int32 align boundary
2199 // int32 fld3 : 4
2200 // }
2201 CHECK_FATAL((allocedBitSize <= UINT32_MAX - fieldBitSize), "must not be zero");
2202 if ((!GetTypeAttrs().IsPacked() && ((allocedBitSize / fieldTypeSizeBits) !=
2203 ((allocedBitSize + fieldBitSize - 1u) / fieldTypeSizeBits))) ||
2204 fieldBitSize == 0) {
2205 // the field is crossing the align boundary of its base type;
2206 // align alloced_size_in_bits to fieldAlign
2207 allocedBitSize = RoundUp(allocedBitSize, fieldTypeSizeBits);
2208 }
2209
2210 // target field id is found
2211 if (curFieldID == fieldID) {
2212 return static_cast<int64>(allocedBitSize);
2213 } else {
2214 ++curFieldID;
2215 }
2216 allocedBitSize += fieldBitSize;
2217 fieldAlignBits = (fieldAlignBits) != 0 ? fieldAlignBits : fieldTypeSizeBits;
2218 allocedSize = std::max(allocedSize, RoundUp(allocedBitSize, fieldAlignBits) / bitsPerByte);
2219 continue;
2220 } // case 1 end
2221
2222 bool leftOverBits = false;
2223 uint64 offset = 0;
2224 // no bit field before current field
2225 if (allocedBitSize == allocedSize * bitsPerByte) {
2226 allocedSize = RoundUp(allocedSize, fieldAlign);
2227 offset = allocedSize;
2228 } else {
2229 CHECK_FATAL((allocedBitSize <= UINT32_MAX - fieldTypeSizeBits), "must not be zero");
2230 // still some leftover bits on allocated words, we calculate things based on bits then.
2231 if (allocedBitSize / fieldAlignBits != (allocedBitSize + fieldTypeSizeBits - 1) / fieldAlignBits) {
2232 // the field is crossing the align boundary of its base type
2233 allocedBitSize = RoundUp(allocedBitSize, static_cast<uint32>(fieldAlignBits));
2234 }
2235 allocedSize = RoundUp(allocedSize, fieldAlign);
2236 offset = (allocedBitSize / fieldAlignBits) * fieldAlign;
2237 leftOverBits = true;
2238 }
2239 // target field id is found
2240 if (curFieldID == fieldID) {
2241 return static_cast<int64>(offset * bitsPerByte);
2242 }
2243 MIRStructType *subStructType = fieldType->EmbeddedStructType();
2244 // case 2 : primtive field;
2245 if (subStructType == nullptr) {
2246 ++curFieldID;
2247 } else {
2248 // case 3 : normal (empty/non-empty) structure(struct/union) field;
2249 // if target field id is in the embedded structure, we should go into it by recursively call
2250 // otherwise, just add the field-id number of the embedded structure, and continue to next field
2251 if ((curFieldID + static_cast<FieldID>(subStructType->NumberOfFieldIDs())) < fieldID) {
2252 curFieldID +=
2253 static_cast<FieldID>(subStructType->NumberOfFieldIDs()) + 1; // 1 represents subStructType itself
2254 } else {
2255 int64 result = subStructType->GetBitOffsetFromBaseAddr(fieldID - curFieldID);
2256 return result + static_cast<int64>(allocedSize * bitsPerByte);
2257 }
2258 }
2259
2260 if (leftOverBits) {
2261 allocedBitSize += fieldTypeSizeBits;
2262 allocedSize =
2263 std::max(allocedSize, RoundUp(allocedBitSize, static_cast<uint32>(fieldAlignBits)) / bitsPerByte);
2264 } else {
2265 allocedSize += fieldTypeSize;
2266 allocedBitSize = allocedSize * bitsPerByte;
2267 }
2268 }
2269 CHECK_FATAL(false, "GetBitOffsetFromStructBaseAddr() fails to find field");
2270 return kOffsetUnknown;
2271 }
2272
GetBitOffsetFromBaseAddr(FieldID fieldID)2273 int64 MIRStructType::GetBitOffsetFromBaseAddr(FieldID fieldID)
2274 {
2275 CHECK_FATAL(fieldID <= static_cast<FieldID>(NumberOfFieldIDs()), "GetBitOffsetFromBaseAddr: fieldID too large");
2276 if (fieldID == 0) {
2277 return 0;
2278 }
2279 switch (GetKind()) {
2280 case kTypeClass: {
2281 // NYI: should know class layout, for different language, the result is different
2282 return kOffsetUnknown; // Invalid offset
2283 }
2284 case kTypeUnion: {
2285 return GetBitOffsetFromUnionBaseAddr(fieldID);
2286 }
2287 case kTypeStruct: {
2288 return GetBitOffsetFromStructBaseAddr(fieldID);
2289 }
2290 default: {
2291 CHECK_FATAL(false, "Wrong type kind for MIRStructType!");
2292 }
2293 }
2294 CHECK_FATAL(false, "Should never reach here!");
2295 return kOffsetUnknown;
2296 }
2297
2298 // compute the offset of the field given by fieldID within the structure type
2299 // structy; it returns the answer in the pair (byteoffset, bitoffset) such that
2300 // if it is a bitfield, byteoffset gives the offset of the container for
2301 // extracting the bitfield and bitoffset is with respect to the current byte
GetFieldOffsetFromBaseAddr(FieldID fieldID) const2302 FieldInfo MIRStructType::GetFieldOffsetFromBaseAddr(FieldID fieldID) const
2303 {
2304 CHECK_FATAL(fieldID <= static_cast<FieldID>(NumberOfFieldIDs()), "GetBitOffsetFromBaseAddr: fieldID too large");
2305 if (GetKind() == kTypeClass || fieldID == 0) {
2306 return {0, 0};
2307 }
2308 if (GetKind() == kTypeUnion || GetKind() == kTypeStruct) {
2309 return const_cast<MIRStructType *>(this)->GetFieldLayout()[fieldID - 1];
2310 }
2311 CHECK_FATAL(false, "Should never reach here!");
2312 return {0, 0};
2313 }
2314
2315 // Whether the memory layout of struct has paddings
HasPadding() const2316 bool MIRStructType::HasPadding() const
2317 {
2318 size_t sumValidSize = 0;
2319 for (uint32 i = 0; i < fields.size(); ++i) {
2320 TyIdxFieldAttrPair pair = GetTyidxFieldAttrPair(i);
2321 MIRType *fieldType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(pair.first);
2322 if (fieldType->IsStructType() && static_cast<MIRStructType *>(fieldType)->HasPadding()) {
2323 return true;
2324 }
2325 sumValidSize += fieldType->GetSize();
2326 }
2327 if (sumValidSize < this->GetSize()) {
2328 return true;
2329 }
2330 return false;
2331 }
2332
2333 // On the ARM platform, when using both zero-sized bitfields and the pack attribute simultaneously,
2334 // the size of a struct should be calculated according to the default alignment without the pack attribute.
HasZeroWidthBitField() const2335 bool MIRStructType::HasZeroWidthBitField() const
2336 {
2337 #ifndef TARGAARCH64
2338 return false;
2339 #endif
2340 for (FieldPair field : fields) {
2341 TyIdx fieldTyIdx = field.second.first;
2342 MIRType *fieldType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(fieldTyIdx);
2343 if (fieldType->GetKind() == kTypeBitField && fieldType->GetSize() == 0) {
2344 return true;
2345 }
2346 }
2347 return false;
2348 }
2349
GetFieldTypeAlignByFieldPair(const FieldPair & fieldPair)2350 uint32 MIRStructType::GetFieldTypeAlignByFieldPair(const FieldPair &fieldPair)
2351 {
2352 MIRType *fieldType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(fieldPair.second.first);
2353 auto fieldAttr = fieldPair.second.second;
2354 auto fieldTypeAlign =
2355 fieldType->GetKind() == kTypeBitField ? GetPrimTypeSize(fieldType->GetPrimType()) : fieldType->GetAlign();
2356 auto fieldPacked = GetTypeAttrs().IsPacked() || fieldAttr.IsPacked();
2357 auto fieldAlign = fieldPacked ? 1u : fieldTypeAlign;
2358 fieldAlign = fieldAttr.HasAligned() ? std::max(fieldAlign, fieldAttr.GetAlign()) : fieldAlign;
2359 return GetTypeAttrs().HasPack() ? std::min(GetTypeAttrs().GetPack(), fieldAlign) : fieldAlign;
2360 }
2361
ComputeUnionLayout()2362 void MIRStructType::ComputeUnionLayout()
2363 {
2364 size = 0;
2365 for (FieldPair &field : fields) {
2366 TyIdx fieldTyIdx = field.second.first;
2367 MIRType *fieldType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(fieldTyIdx);
2368 MIRStructType *subStructType = fieldType->EmbeddedStructType();
2369 size = std::max(fieldType->GetSize(), size);
2370 AddFieldLayout({0, 0, field});
2371 if (subStructType != nullptr) {
2372 // if target field id is in the embedded structure, we should go into it by recursively call
2373 // otherwise, just add the field-id number of the embedded structure, and continue to next field
2374 auto &subStructFieldLayout = subStructType->GetFieldLayout();
2375 (void)fieldLayout.insert(fieldLayout.end(), subStructFieldLayout.begin(), subStructFieldLayout.end());
2376 }
2377 }
2378 if (GetTypeAttrs().IsTypedef()) {
2379 size = RoundUp(size, GetTypedefOriginalAlign());
2380 } else {
2381 size = RoundUp(size, GetAlign());
2382 }
2383 CHECK_FATAL(fieldLayout.size() == NumberOfFieldIDs(), "fields layout != fieldID size");
2384 layoutComputed = true;
2385 }
2386
ComputeLayout()2387 void MIRStructType::ComputeLayout()
2388 {
2389 if (layoutComputed) {
2390 return;
2391 }
2392 if (GetKind() == kTypeUnion) {
2393 ComputeUnionLayout();
2394 return;
2395 }
2396 uint32 allocedSize = 0; // space need for all fields before currentField
2397 uint32 allocedBitSize = 0;
2398 auto hasPack = GetTypeAttrs().HasPack();
2399 auto packed = GetTypeAttrs().IsPacked();
2400 constexpr uint8 bitsPerByte = 8; // 8 bits per byte
2401 for (FieldPair &fieldPair : fields) {
2402 auto tyIdxFieldAttrPair = fieldPair.second;
2403 TyIdx fieldTyIdx = tyIdxFieldAttrPair.first;
2404 auto fieldAttr = tyIdxFieldAttrPair.second;
2405 MIRType *fieldType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(fieldTyIdx);
2406 auto fieldPacked = packed || fieldAttr.IsPacked();
2407 uint32 fieldAlign = GetFieldTypeAlignByFieldPair(fieldPair);
2408 uint32 fieldAlignBits = fieldAlign * bitsPerByte;
2409 uint32 fieldBitSize;
2410 uint32 fieldTypeSize = static_cast<uint32>(fieldType->GetSize());
2411 uint32 fieldTypeSizeBits = fieldTypeSize * bitsPerByte;
2412 // case 1 : bitfield (including zero-width bitfield);
2413 if (fieldType->GetKind() == kTypeBitField) {
2414 fieldBitSize = static_cast<MIRBitFieldType *>(fieldType)->GetFieldSize();
2415 fieldTypeSizeBits = static_cast<uint32>(GetPrimTypeSize(fieldType->GetPrimType())) * bitsPerByte;
2416 // zero bit field
2417 CHECK_FATAL((allocedBitSize <= UINT32_MAX - fieldBitSize), "must not be zero");
2418 if (fieldAttr.HasAligned()) {
2419 if ((fieldAttr.GetAlign() < fieldAlign &&
2420 fieldAttr.GetAlign() <= ((fieldTypeSizeBits - fieldBitSize) / bitsPerByte))) {
2421 allocedBitSize = RoundUp(allocedBitSize, fieldAttr.GetAlign() * bitsPerByte);
2422 } else {
2423 allocedBitSize = RoundUp(allocedBitSize, fieldAlignBits);
2424 }
2425 } else if ((!hasPack && !fieldPacked &&
2426 ((allocedBitSize / fieldTypeSizeBits) !=
2427 ((allocedBitSize + fieldBitSize - 1u) / fieldTypeSizeBits))) ||
2428 fieldBitSize == 0) {
2429 // the field is crossing the align boundary of its base type;
2430 // align alloced_size_in_bits to fieldAlign
2431 allocedBitSize = RoundUp(allocedBitSize, fieldTypeSizeBits);
2432 }
2433 auto info =
2434 FieldInfo((allocedBitSize / fieldAlignBits) * fieldAlign, allocedBitSize % fieldAlignBits, fieldPair);
2435 AddFieldLayout(info);
2436 allocedBitSize += fieldBitSize;
2437 fieldAlignBits = (fieldAlignBits) != 0 ? fieldAlignBits : fieldTypeSizeBits;
2438 allocedSize =
2439 std::max(allocedSize, static_cast<uint32>(RoundUp(allocedBitSize, fieldAlignBits) / bitsPerByte));
2440 continue;
2441 } // case 1 end
2442
2443 bool leftOverBits = false;
2444 uint32 offset = 0;
2445 // no bit field before current field
2446 if (allocedBitSize == allocedSize * bitsPerByte) {
2447 allocedSize = RoundUp(allocedSize, fieldAlign);
2448 offset = allocedSize;
2449 } else {
2450 CHECK_FATAL((allocedBitSize <= UINT32_MAX - fieldTypeSizeBits), "must not be zero");
2451 // still some leftover bits on allocated words, we calculate things based on bits then.
2452 if ((allocedBitSize / fieldAlignBits != (allocedBitSize + fieldTypeSizeBits - 1) / fieldAlignBits) ||
2453 fieldTypeSize == 0) {
2454 // the field is crossing the align boundary of its base type
2455 allocedBitSize = RoundUp(allocedBitSize, static_cast<uint32>(fieldAlignBits));
2456 }
2457 allocedSize = RoundUp(allocedSize, fieldAlign);
2458 offset = (allocedBitSize / fieldAlignBits) * fieldAlign;
2459 leftOverBits = true;
2460 }
2461 // target field id is found
2462 MIRStructType *subStructType = fieldType->EmbeddedStructType();
2463 // case 2 : primitive field;
2464 AddFieldLayout({offset, 0, fieldPair});
2465 if (subStructType != nullptr) {
2466 // case 3 : normal (empty/non-empty) structure(struct/union) field;
2467 // if target field id is in the embedded structure, we should go into it by recursively call
2468 // otherwise, just add the field-id number of the embedded structure, and continue to next field
2469 auto &subStructFieldOffsets = subStructType->GetFieldLayout();
2470 for (FieldInfo layout : subStructFieldOffsets) {
2471 auto convertedLayout = layout;
2472 convertedLayout.byteOffset += offset;
2473 AddFieldLayout(convertedLayout);
2474 }
2475 }
2476 if (leftOverBits) {
2477 allocedBitSize += fieldTypeSizeBits;
2478 allocedSize =
2479 std::max(allocedSize, static_cast<uint32>(RoundUp(allocedBitSize, fieldAlignBits) / bitsPerByte));
2480 } else if (!static_cast<MIRArrayType *>(fieldType)->IsIncompleteArray()) {
2481 allocedSize += fieldTypeSize;
2482 allocedBitSize = allocedSize * bitsPerByte;
2483 }
2484 }
2485 if (GetTypeAttrs().IsTypedef()) {
2486 allocedSize = RoundUp(allocedSize, GetTypedefOriginalAlign());
2487 } else {
2488 allocedSize = RoundUp(allocedSize, GetAlign());
2489 }
2490 size = allocedSize;
2491 CHECK_FATAL(fieldLayout.size() == NumberOfFieldIDs(), "fields layout != fieldID size");
2492 layoutComputed = true;
2493 }
2494
2495 // set hasVolatileField to true if parent type has volatile field, otherwise flase.
ParentTypeHasVolatileField(const TyIdx parentTyIdx,bool & hasVolatileField)2496 static bool ParentTypeHasVolatileField(const TyIdx parentTyIdx, bool &hasVolatileField)
2497 {
2498 hasVolatileField = (GlobalTables::GetTypeTable().GetTypeFromTyIdx(parentTyIdx)->HasVolatileField());
2499 return hasVolatileField;
2500 }
2501
2502 // go through all the fields to check if there is volatile attribute set;
HasVolatileField() const2503 bool MIRClassType::HasVolatileField() const
2504 {
2505 return MIRStructType::HasVolatileField() ||
2506 (parentTyIdx != 0u && ParentTypeHasVolatileField(parentTyIdx, hasVolatileField));
2507 }
2508
2509 // go through all the fields to check if there is volatile attribute set;
HasVolatileField() const2510 bool MIRInterfaceType::HasVolatileField() const
2511 {
2512 if (MIRStructType::HasVolatileField()) {
2513 return true;
2514 }
2515 for (TyIdx parentTypeIdx : parentsTyIdx) {
2516 if (ParentTypeHasVolatileField(parentTypeIdx, hasVolatileField)) {
2517 return true;
2518 }
2519 }
2520 return false;
2521 }
2522
HasTypeParamInFields(const FieldVector & fieldsOfStruct) const2523 bool MIRStructType::HasTypeParamInFields(const FieldVector &fieldsOfStruct) const
2524 {
2525 for (const FieldPair &field : fieldsOfStruct) {
2526 if (field.second.second.GetAttr(FLDATTR_generic)) {
2527 return true;
2528 }
2529 }
2530 return false;
2531 }
2532
2533 // go through all the fields to check if there is generic attribute set;
HasTypeParam() const2534 bool MIRStructType::HasTypeParam() const
2535 {
2536 return HasTypeParamInFields(fields) || HasTypeParamInFields(parentFields);
2537 }
2538
HasTypeParam() const2539 bool MIRClassType::HasTypeParam() const
2540 {
2541 return MIRStructType::HasTypeParam() ||
2542 (parentTyIdx != 0u && GlobalTables::GetTypeTable().GetTypeFromTyIdx(parentTyIdx)->HasTypeParam());
2543 }
2544
HasTypeParam() const2545 bool MIRInterfaceType::HasTypeParam() const
2546 {
2547 if (MIRStructType::HasTypeParam()) {
2548 return true;
2549 }
2550 // check if the parent classes have type parameter
2551 for (TyIdx parentTypeIdx : parentsTyIdx) {
2552 if (GlobalTables::GetTypeTable().GetTypeFromTyIdx(parentTypeIdx)->HasTypeParam()) {
2553 return true;
2554 }
2555 }
2556 return false;
2557 }
2558
NumberOfFieldIDs() const2559 uint32 MIRClassType::NumberOfFieldIDs() const
2560 {
2561 if (fieldsNum != kInvalidFieldNum) {
2562 return fieldsNum;
2563 }
2564 size_t parentFieldIDs = 0;
2565 if (parentTyIdx != TyIdx(0)) {
2566 MIRType *parentty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(parentTyIdx);
2567 parentFieldIDs = parentty->NumberOfFieldIDs();
2568 }
2569 fieldsNum = parentFieldIDs + MIRStructType::NumberOfFieldIDs();
2570 return fieldsNum;
2571 }
2572
TraverseToFieldRef(FieldID & fieldID) const2573 FieldPair MIRClassType::TraverseToFieldRef(FieldID &fieldID) const
2574 {
2575 if (parentTyIdx != 0u) {
2576 auto *parentClassType = static_cast<MIRClassType *>(GlobalTables::GetTypeTable().GetTypeFromTyIdx(parentTyIdx));
2577 if (parentClassType != nullptr) {
2578 --fieldID;
2579 const FieldPair &curPair = parentClassType->TraverseToFieldRef(fieldID);
2580 if (fieldID == 1 && curPair.second.first != 0u) {
2581 return curPair;
2582 }
2583 }
2584 }
2585 return MIRStructType::TraverseToFieldRef(fieldID);
2586 }
2587
2588 // fields in interface are all static and are global, won't be accessed through fields
TraverseToFieldRef(FieldID & fieldID) const2589 FieldPair MIRInterfaceType::TraverseToFieldRef(FieldID &fieldID) const
2590 {
2591 return {GStrIdx(0), TyIdxFieldAttrPair(TyIdx(0), FieldAttrs())};
2592 }
2593
IsPointedTypeVolatile(int fieldID) const2594 bool MIRPtrType::IsPointedTypeVolatile(int fieldID) const
2595 {
2596 if (typeAttrs.GetAttr(ATTR_volatile)) {
2597 return true;
2598 }
2599 MIRType *pointedTy = GlobalTables::GetTypeTable().GetTypeFromTyIdx(GetPointedTyIdx());
2600 return pointedTy->IsVolatile(fieldID);
2601 }
2602
IsUnsafeType() const2603 bool MIRPtrType::IsUnsafeType() const
2604 {
2605 if (GetTypeAttrs().GetAttr(ATTR_may_alias)) {
2606 return true;
2607 }
2608 // Check for <* void>/<* i8/u8>
2609 MIRType *pointedType = GetPointedType();
2610 while (pointedType->IsMIRPtrType()) {
2611 pointedType = static_cast<MIRPtrType *>(pointedType)->GetPointedType();
2612 }
2613 return (pointedType->GetPrimType() == PTY_void || pointedType->GetSize() == 1);
2614 }
2615
IsVoidPointer() const2616 bool MIRPtrType::IsVoidPointer() const
2617 {
2618 return GlobalTables::GetTypeTable().GetVoidPtr() == this;
2619 }
2620
GetSize() const2621 size_t MIRPtrType::GetSize() const
2622 {
2623 return GetPointerSize();
2624 }
GetAlign() const2625 uint32 MIRPtrType::GetAlign() const
2626 {
2627 return GetPointerSize();
2628 }
2629
GetPointedTyIdxFldAttrPairWithFieldID(FieldID fldId) const2630 TyIdxFieldAttrPair MIRPtrType::GetPointedTyIdxFldAttrPairWithFieldID(FieldID fldId) const
2631 {
2632 if (fldId == 0) {
2633 return TyIdxFieldAttrPair(pointedTyIdx, FieldAttrs());
2634 }
2635 MIRType *ty = GlobalTables::GetTypeTable().GetTypeFromTyIdx(pointedTyIdx);
2636 MIRStructType *structTy = ty->EmbeddedStructType();
2637 if (structTy == nullptr) {
2638 // this can happen due to casting in C; just return the pointed to type
2639 return TyIdxFieldAttrPair(pointedTyIdx, FieldAttrs());
2640 }
2641 return structTy->TraverseToField(fldId).second;
2642 }
2643
GetPointedTyIdxWithFieldID(FieldID fieldID) const2644 TyIdx MIRPtrType::GetPointedTyIdxWithFieldID(FieldID fieldID) const
2645 {
2646 return GetPointedTyIdxFldAttrPairWithFieldID(fieldID).first;
2647 }
2648
GetMplTypeName() const2649 std::string MIRPtrType::GetMplTypeName() const
2650 {
2651 std::stringstream ss;
2652 ss << "<* ";
2653 MIRType *pointedType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(pointedTyIdx);
2654 CHECK_FATAL(pointedType != nullptr, "invalid ptr type");
2655 ss << pointedType->GetMplTypeName();
2656 ss << ">";
2657 return ss.str();
2658 }
2659
GetCompactMplTypeName() const2660 std::string MIRPtrType::GetCompactMplTypeName() const
2661 {
2662 MIRType *pointedType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(pointedTyIdx);
2663 CHECK_FATAL(pointedType != nullptr, "invalid ptr type");
2664 return pointedType->GetCompactMplTypeName();
2665 }
2666
GetPointedFuncType() const2667 MIRFuncType *MIRPtrType::GetPointedFuncType() const
2668 {
2669 MIRType *pointedType = GetPointedType();
2670 if (pointedType->GetKind() == kTypeFunction) {
2671 return static_cast<MIRFuncType *>(pointedType);
2672 }
2673 if (pointedType->GetKind() == kTypePointer) {
2674 MIRPtrType *pointedPtrType = static_cast<MIRPtrType *>(pointedType);
2675 if (pointedPtrType->GetPointedType()->GetKind() == kTypeFunction) {
2676 return static_cast<MIRFuncType *>(pointedPtrType->GetPointedType());
2677 }
2678 }
2679 return nullptr;
2680 }
2681
NumberOfFieldIDs() const2682 uint32 MIRStructType::NumberOfFieldIDs() const
2683 {
2684 if (fieldsNum != kInvalidFieldNum) {
2685 return fieldsNum;
2686 }
2687 fieldsNum = 0;
2688 for (FieldPair curpair : fields) {
2689 ++fieldsNum;
2690 MIRType *curfieldtype = GlobalTables::GetTypeTable().GetTypeFromTyIdx(curpair.second.first);
2691 fieldsNum += curfieldtype->NumberOfFieldIDs();
2692 }
2693 return fieldsNum;
2694 }
2695
ConvertToTypeAttrs()2696 TypeAttrs FieldAttrs::ConvertToTypeAttrs()
2697 {
2698 TypeAttrs attr;
2699 constexpr uint32 maxAttrNum = 64;
2700 for (uint32 i = 0; i < maxAttrNum; ++i) {
2701 if ((attrFlag & (1ULL << i)) == 0) {
2702 continue;
2703 }
2704 auto attrKind = static_cast<FieldAttrKind>(i);
2705 switch (attrKind) {
2706 #define FIELD_ATTR
2707 #define ATTR(STR) \
2708 case FLDATTR_##STR: \
2709 attr.SetAttr(ATTR_##STR); \
2710 break;
2711 #include "all_attributes.def"
2712 #undef ATTR
2713 #undef FIELD_ATTR
2714 default:
2715 DEBUG_ASSERT(false, "unknown TypeAttrs");
2716 break;
2717 }
2718 }
2719 return attr;
2720 }
2721
GetElemType(const MIRType & arrayType)2722 MIRType *GetElemType(const MIRType &arrayType)
2723 {
2724 if (arrayType.GetKind() == kTypeArray) {
2725 return static_cast<const MIRArrayType &>(arrayType).GetElemType();
2726 } else if (arrayType.GetKind() == kTypeFArray) {
2727 return static_cast<const MIRFarrayType &>(arrayType).GetElemType();
2728 } else if (arrayType.GetKind() == kTypeJArray) {
2729 return static_cast<const MIRJarrayType &>(arrayType).GetElemType();
2730 }
2731 return nullptr;
2732 }
2733
2734 #ifdef TARGAARCH64
2735 static constexpr size_t kMaxHfaOrHvaElemNumber = 4;
2736
CheckHomogeneousAggregatesBaseType(PrimType type)2737 bool CheckHomogeneousAggregatesBaseType(PrimType type)
2738 {
2739 if (type == PTY_f32 || type == PTY_f64 || type == PTY_f128 || IsPrimitiveVector(type)) {
2740 return true;
2741 }
2742 return false;
2743 }
2744
IsSameHomogeneousAggregatesBaseType(PrimType type,PrimType nextType)2745 bool IsSameHomogeneousAggregatesBaseType(PrimType type, PrimType nextType)
2746 {
2747 if ((type == PTY_f32 || type == PTY_f64 || type == PTY_f128) && type == nextType) {
2748 return true;
2749 } else if (IsPrimitiveVector(type) && IsPrimitiveVector(nextType) &&
2750 GetPrimTypeSize(type) == GetPrimTypeSize(nextType)) {
2751 return true;
2752 }
2753 return false;
2754 }
2755
IsUnionHomogeneousAggregates(const MIRStructType & ty,PrimType & primType,size_t & elemNum)2756 bool IsUnionHomogeneousAggregates(const MIRStructType &ty, PrimType &primType, size_t &elemNum)
2757 {
2758 primType = PTY_begin;
2759 elemNum = 0;
2760 for (const auto &field : ty.GetFields()) {
2761 MIRType *filedType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(field.second.first);
2762 if (filedType->GetSize() == 0) {
2763 continue;
2764 }
2765 PrimType filedPrimType = PTY_begin;
2766 size_t filedElemNum = 0;
2767 if (!IsHomogeneousAggregates(*filedType, filedPrimType, filedElemNum, false)) {
2768 return false;
2769 }
2770 primType = (primType == PTY_begin) ? filedPrimType : primType;
2771 if (!IsSameHomogeneousAggregatesBaseType(primType, filedPrimType)) {
2772 return false;
2773 }
2774 elemNum = std::max(elemNum, filedElemNum);
2775 }
2776 return (ty.GetSize() == static_cast<uint32>(GetPrimTypeSize(primType) * elemNum));
2777 }
2778
IsStructHomogeneousAggregates(const MIRStructType & ty,PrimType & primType,size_t & elemNum)2779 bool IsStructHomogeneousAggregates(const MIRStructType &ty, PrimType &primType, size_t &elemNum)
2780 {
2781 primType = PTY_begin;
2782 elemNum = 0;
2783 FieldID fieldsNum = 0;
2784
2785 for (const auto &field : ty.GetFields()) {
2786 ++fieldsNum;
2787 MIRType *filedType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(field.second.first);
2788 if (elemNum != 0 && primType != PTY_begin) {
2789 uint32 curOffset = static_cast<uint32>(GetPrimTypeSize(primType) * elemNum);
2790 if (curOffset != ty.GetFieldOffsetFromBaseAddr(fieldsNum).byteOffset) {
2791 return false;
2792 }
2793 }
2794 fieldsNum += static_cast<FieldID>(filedType->NumberOfFieldIDs());
2795 if (filedType->GetSize() == 0) {
2796 continue;
2797 }
2798 PrimType filedPrimType = PTY_begin;
2799 size_t filedElemNum = 0;
2800 if (!IsHomogeneousAggregates(*filedType, filedPrimType, filedElemNum, false)) {
2801 return false;
2802 }
2803 elemNum += filedElemNum;
2804 primType = (primType == PTY_begin) ? filedPrimType : primType;
2805 if (elemNum > kMaxHfaOrHvaElemNumber || !IsSameHomogeneousAggregatesBaseType(primType, filedPrimType)) {
2806 return false;
2807 }
2808 }
2809 return (ty.GetSize() == static_cast<uint32>(GetPrimTypeSize(primType) * elemNum));
2810 }
2811
IsArrayHomogeneousAggregates(const MIRArrayType & ty,PrimType & primType,size_t & elemNum)2812 bool IsArrayHomogeneousAggregates(const MIRArrayType &ty, PrimType &primType, size_t &elemNum)
2813 {
2814 primType = PTY_begin;
2815 elemNum = 0;
2816 MIRType *elemMirType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(ty.GetElemTyIdx());
2817 if (!IsHomogeneousAggregates(*elemMirType, primType, elemNum, false)) {
2818 return false;
2819 }
2820 elemNum *= ty.ElemNumber();
2821 if (elemNum > kMaxHfaOrHvaElemNumber) {
2822 return false;
2823 }
2824 uint32 needSize = static_cast<uint32>(GetPrimTypeSize(primType) * elemNum);
2825 return (ty.GetSize() == needSize);
2826 }
2827
IsHomogeneousAggregates(const MIRType & ty,PrimType & primType,size_t & elemNum,bool firstDepth)2828 bool IsHomogeneousAggregates(const MIRType &ty, PrimType &primType, size_t &elemNum, bool firstDepth)
2829 {
2830 if (firstDepth && ty.GetKind() == kTypeUnion) {
2831 return IsUnionHomogeneousAggregates(static_cast<const MIRStructType &>(ty), primType, elemNum);
2832 }
2833 if (firstDepth && ty.GetKind() != kTypeStruct) {
2834 return false;
2835 }
2836 primType = PTY_begin;
2837 elemNum = 0;
2838 if (ty.GetKind() == kTypeStruct) {
2839 auto &structType = static_cast<const MIRStructType &>(ty);
2840 return IsStructHomogeneousAggregates(structType, primType, elemNum);
2841 } else if (ty.GetKind() == kTypeUnion) {
2842 auto &unionType = static_cast<const MIRStructType &>(ty);
2843 return IsUnionHomogeneousAggregates(unionType, primType, elemNum);
2844 } else if (ty.GetKind() == kTypeArray) {
2845 auto &arrType = static_cast<const MIRArrayType &>(ty);
2846 return IsArrayHomogeneousAggregates(arrType, primType, elemNum);
2847 } else {
2848 primType = ty.GetPrimType();
2849 elemNum = 1;
2850 if (!CheckHomogeneousAggregatesBaseType(primType)) {
2851 return false;
2852 }
2853 }
2854 return (elemNum != 0);
2855 }
2856
IsParamStructCopyToMemory(const MIRType & ty)2857 bool IsParamStructCopyToMemory(const MIRType &ty)
2858 {
2859 if (ty.GetPrimType() == PTY_agg) {
2860 PrimType primType = PTY_begin;
2861 size_t elemNum = 0;
2862 return !IsHomogeneousAggregates(ty, primType, elemNum) && ty.GetSize() > k16BitSize;
2863 }
2864 return false;
2865 }
2866
IsReturnInMemory(const MIRType & ty)2867 bool IsReturnInMemory(const MIRType &ty)
2868 {
2869 if (ty.GetPrimType() == PTY_agg) {
2870 PrimType primType = PTY_begin;
2871 size_t elemNum = 0;
2872 return !IsHomogeneousAggregates(ty, primType, elemNum) && ty.GetSize() > k16BitSize;
2873 }
2874 return false;
2875 }
2876 #else
IsParamStructCopyToMemory(const MIRType & ty)2877 bool IsParamStructCopyToMemory(const MIRType &ty)
2878 {
2879 return ty.GetPrimType() == PTY_agg && ty.GetSize() > k16BitSize;
2880 }
2881
IsReturnInMemory(const MIRType & ty)2882 bool IsReturnInMemory(const MIRType &ty)
2883 {
2884 return ty.GetPrimType() == PTY_agg && ty.GetSize() > k16BitSize;
2885 }
2886 #endif // TARGAARCH64
2887 } // namespace maple
2888 #endif // MIR_FEATURE_FULL
2889