• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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