[clang] eaca933 - [Clang][CodeGen]Fix __builtin_dump_struct missing record type field name

via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 28 22:22:09 PDT 2022


Author: jonasyhwang
Date: 2022-04-29T12:58:53+08:00
New Revision: eaca933c59fd61b3df4697b5fae0eeec67acfaeb

URL: https://github.com/llvm/llvm-project/commit/eaca933c59fd61b3df4697b5fae0eeec67acfaeb
DIFF: https://github.com/llvm/llvm-project/commit/eaca933c59fd61b3df4697b5fae0eeec67acfaeb.diff

LOG: [Clang][CodeGen]Fix __builtin_dump_struct missing record type field name

Thanks for @rsmith to point this. I'm sorry for introducing this bug.
See @rsmith 's comment in https://reviews.llvm.org/D122248
Eg:(By @rsmith ) https://godbolt.org/z/o7vcbWaEf
I have added a test case
struct:
```
struct U19A {
    int a;
  };
  struct U19B {
    struct U19A a;
  };

  struct U19B a = {
    .a.a = 2022
  };
```
Dump result:
```
struct U19B {
    struct U19A a = {
        int a = 2022
    }
}
```

Reviewed By: erichkeane

Differential Revision: https://reviews.llvm.org/D122920

Added: 
    

Modified: 
    clang/lib/CodeGen/CGBuiltin.cpp
    clang/test/CodeGen/dump-struct-builtin.c

Removed: 
    


################################################################################
diff  --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp
index f9966c1fd777..83fd75fd9667 100644
--- a/clang/lib/CodeGen/CGBuiltin.cpp
+++ b/clang/lib/CodeGen/CGBuiltin.cpp
@@ -24,6 +24,7 @@
 #include "clang/AST/Attr.h"
 #include "clang/AST/Decl.h"
 #include "clang/AST/OSLog.h"
+#include "clang/AST/FormatString.h"
 #include "clang/Basic/TargetBuiltins.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/CodeGen/CGFunctionInfo.h"
@@ -2043,47 +2044,39 @@ EmitCheckedMixedSignMultiply(CodeGenFunction &CGF, const clang::Expr *Op1,
   return RValue::get(Overflow);
 }
 
-static llvm::Value *dumpRecord(CodeGenFunction &CGF, QualType RType,
-                               LValue RecordLV, CharUnits Align,
-                               llvm::FunctionCallee Func, int Lvl) {
-  ASTContext &Context = CGF.getContext();
+static std::string getPrintfSpecifier(CodeGenFunction &CGF, QualType QT) {
+  analyze_printf::PrintfSpecifier spec;
+  if (!spec.fixType(QT, CGF.getLangOpts(), CGF.getContext(), false)) {
+    // If this type is a boolean type, we should use '%d' to dump its value.
+    if (QT->isBooleanType())
+      return "%d";
+
+    // Otherwise, in order to keep the same behavior as before, use '%p' for
+    // unknown types
+    return "%p";
+  }
+  std::string str;
+  llvm::raw_string_ostream ss(str);
+  spec.toString(ss);
+  return str;
+}
+
+static llvm::Value *dumpValue(CodeGenFunction &CGF, QualType RType,
+                              LValue RecordLV, CharUnits Align,
+                              llvm::FunctionCallee Func, PrintingPolicy Policy,
+                              int Lvl) {
   RecordDecl *RD = RType->castAs<RecordType>()->getDecl()->getDefinition();
   std::string Pad = std::string(Lvl * 4, ' ');
   std::string ElementPad = std::string((Lvl + 1) * 4, ' ');
 
-  PrintingPolicy Policy(Context.getLangOpts());
-  Policy.AnonymousTagLocations = false;
-  Value *GString = CGF.Builder.CreateGlobalStringPtr(
-    llvm::Twine(Pad).concat(RType.getAsString(Policy)).concat(" {\n").str());
+  Value *GString = CGF.Builder.CreateGlobalStringPtr("{\n");
   Value *Res = CGF.Builder.CreateCall(Func, {GString});
 
-  static llvm::DenseMap<QualType, const char *> Types;
-  if (Types.empty()) {
-    Types[Context.CharTy] = "%c";
-    Types[Context.BoolTy] = "%d";
-    Types[Context.SignedCharTy] = "%hhd";
-    Types[Context.UnsignedCharTy] = "%hhu";
-    Types[Context.IntTy] = "%d";
-    Types[Context.UnsignedIntTy] = "%u";
-    Types[Context.LongTy] = "%ld";
-    Types[Context.UnsignedLongTy] = "%lu";
-    Types[Context.LongLongTy] = "%lld";
-    Types[Context.UnsignedLongLongTy] = "%llu";
-    Types[Context.ShortTy] = "%hd";
-    Types[Context.UnsignedShortTy] = "%hu";
-    Types[Context.VoidPtrTy] = "%p";
-    Types[Context.FloatTy] = "%f";
-    Types[Context.DoubleTy] = "%f";
-    Types[Context.LongDoubleTy] = "%Lf";
-    Types[Context.getPointerType(Context.CharTy)] = "%s";
-    Types[Context.getPointerType(Context.getConstType(Context.CharTy))] = "%s";
-  }
-
   for (const auto *FD : RD->fields()) {
     Value *TmpRes = nullptr;
 
     std::string Format = llvm::Twine(ElementPad)
-                             .concat(FD->getType().getAsString())
+                             .concat(FD->getType().getAsString(Policy))
                              .concat(llvm::Twine(' '))
                              .concat(FD->getNameAsString())
                              .str();
@@ -2108,31 +2101,36 @@ static llvm::Value *dumpRecord(CodeGenFunction &CGF, QualType RType,
       }
     }
 
+    GString = CGF.Builder.CreateGlobalStringPtr(
+        llvm::Twine(Format).concat(" = ").str());
+    TmpRes = CGF.Builder.CreateCall(Func, {GString});
+    Res = CGF.Builder.CreateAdd(TmpRes, Res);
+
     LValue FieldLV = CGF.EmitLValueForField(RecordLV, FD);
     QualType CanonicalType =
         FD->getType().getUnqualifiedType().getCanonicalType();
 
     // We check whether we are in a recursive type
     if (CanonicalType->isRecordType()) {
-      TmpRes = dumpRecord(CGF, CanonicalType, FieldLV, Align, Func, Lvl + 1);
+
+      // If current field is a record type, we should not dump the type name in
+      // recursive dumpRecord call, and we only dump the things between {...}
+      TmpRes =
+          dumpValue(CGF, CanonicalType, FieldLV, Align, Func, Policy, Lvl + 1);
       Res = CGF.Builder.CreateAdd(TmpRes, Res);
       continue;
     }
 
     // We try to determine the best format to print the current field
-    const char *TypeFormat = Types.find(CanonicalType) == Types.end()
-                                 ? Types[Context.VoidPtrTy]
-                                 : Types[CanonicalType];
-
-    GString = CGF.Builder.CreateGlobalStringPtr(llvm::Twine(Format)
-                                                    .concat(" = ")
-                                                    .concat(TypeFormat)
-                                                    .concat(llvm::Twine('\n'))
-                                                    .str());
+    std::string PrintFormatSpec = getPrintfSpecifier(CGF, FD->getType());
+    GString = CGF.Builder.CreateGlobalStringPtr(
+        llvm::Twine(PrintFormatSpec).concat(llvm::Twine('\n')).str());
 
     RValue RV = FD->isBitField()
                     ? CGF.EmitLoadOfBitfieldLValue(FieldLV, FD->getLocation())
                     : CGF.EmitLoadOfLValue(FieldLV, FD->getLocation());
+
+    /// FIXME: This place needs type promotion.
     TmpRes = CGF.Builder.CreateCall(Func, {GString, RV.getScalarVal()});
     Res = CGF.Builder.CreateAdd(Res, TmpRes);
   }
@@ -2143,6 +2141,20 @@ static llvm::Value *dumpRecord(CodeGenFunction &CGF, QualType RType,
   return Res;
 }
 
+static llvm::Value *dumpRecord(CodeGenFunction &CGF, QualType RType,
+                               LValue RecordLV, CharUnits Align,
+                               llvm::FunctionCallee Func) {
+  ASTContext &Context = CGF.getContext();
+  PrintingPolicy Policy(Context.getLangOpts());
+  Policy.AnonymousTagLocations = false;
+  std::string Name = llvm::Twine(RType.getAsString(Policy)).concat(" ").str();
+  Value *GString = CGF.Builder.CreateGlobalStringPtr(Name);
+  Value *Res = CGF.Builder.CreateCall(Func, {GString});
+  Value *TmpRes = dumpValue(CGF, RType, RecordLV, Align, Func, Policy, 0);
+  Res = CGF.Builder.CreateAdd(Res, TmpRes);
+  return Res;
+}
+
 static bool
 TypeRequiresBuiltinLaunderImp(const ASTContext &Ctx, QualType Ty,
                               llvm::SmallPtrSetImpl<const Decl *> &Seen) {
@@ -2683,7 +2695,7 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
     Value *RecordPtr = EmitScalarExpr(Arg0);
     LValue RecordLV = MakeAddrLValue(RecordPtr, Arg0Type, Arg0Align);
     Value *Res = dumpRecord(*this, Arg0Type, RecordLV, Arg0Align,
-                            {LLVMFuncType, Func}, 0);
+                            {LLVMFuncType, Func});
     return RValue::get(Res);
   }
 

diff  --git a/clang/test/CodeGen/dump-struct-builtin.c b/clang/test/CodeGen/dump-struct-builtin.c
index 2fdc815f35d2..730119c897dd 100644
--- a/clang/test/CodeGen/dump-struct-builtin.c
+++ b/clang/test/CodeGen/dump-struct-builtin.c
@@ -4,95 +4,148 @@
 #include <stdint.h>
 
 // CHECK: @__const.unit1.a = private unnamed_addr constant %struct.U1A { i16 12 }, align 2
-// CHECK-NEXT: [[STRUCT_STR_U1:@[0-9]+]] = private unnamed_addr constant [14 x i8] c"struct U1A {\0A\00", align 1
-// CHECK-NEXT: [[FIELD_U1:@[0-9]+]] = private unnamed_addr constant [19 x i8] c"    short a = %hd\0A\00", align 1
-// CHECK-NEXT: [[END_STRUCT_U1:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_STR_U1:@[0-9]+]] = private unnamed_addr constant [12 x i8] c"struct U1A \00", align 1
+// CHECK-NEXT: [[STRUCT_L_BRACE_U1:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"{\0A\00", align 1
+// CHECK-NEXT: [[FIELD_U1:@[0-9]+]] = private unnamed_addr constant [15 x i8] c"    short a = \00", align 1
+// CHECK-NEXT: [[FORMAT_U1:@[0-9]+]] = private unnamed_addr constant [5 x i8] c"%hd\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_R_BRACE_U1:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
 
 // CHECK: @__const.unit2.a = private unnamed_addr constant %struct.U2A { i16 12 }, align 2
-// CHECK-NEXT: [[STRUCT_STR_U2:@[0-9]+]] = private unnamed_addr constant [14 x i8] c"struct U2A {\0A\00", align 1
-// CHECK-NEXT: [[FIELD_U2:@[0-9]+]] = private unnamed_addr constant [28 x i8] c"    unsigned short a = %hu\0A\00", align 1
-// CHECK-NEXT: [[END_STRUCT_U2:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_STR_U2:@[0-9]+]] = private unnamed_addr constant [12 x i8] c"struct U2A \00", align 1
+// CHECK-NEXT: [[STRUCT_L_BRACE_U2:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"{\0A\00", align 1
+// CHECK-NEXT: [[FIELD_U2:@[0-9]+]] = private unnamed_addr constant [24 x i8] c"    unsigned short a = \00", align 1
+// CHECK-NEXT: [[FORMAT_U2:@[0-9]+]] = private unnamed_addr constant [5 x i8] c"%hu\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_R_BRACE_U2:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
 
 // CHECK: @__const.unit3.a = private unnamed_addr constant %struct.U3A { i32 12 }, align 4
-// CHECK-NEXT: [[STRUCT_STR_U3:@[0-9]+]] = private unnamed_addr constant [14 x i8] c"struct U3A {\0A\00", align 1
-// CHECK-NEXT: [[FIELD_U3:@[0-9]+]] = private unnamed_addr constant [16 x i8] c"    int a = %d\0A\00", align 1
-// CHECK-NEXT: [[END_STRUCT_U3:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_STR_U3:@[0-9]+]] = private unnamed_addr constant [12 x i8] c"struct U3A \00", align 1
+// CHECK-NEXT: [[STRUCT_L_BRACE_U3:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"{\0A\00", align 1
+// CHECK-NEXT: [[FIELD_U3:@[0-9]+]] = private unnamed_addr constant [13 x i8] c"    int a = \00", align 1
+// CHECK-NEXT: [[FORMAT_U3:@[0-9]+]] = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_R_BRACE_U3:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
 
 // CHECK: @__const.unit4.a = private unnamed_addr constant %struct.U4A { i32 12 }, align 4
-// CHECK-NEXT: [[STRUCT_STR_U4:@[0-9]+]] = private unnamed_addr constant [14 x i8] c"struct U4A {\0A\00", align 1
-// CHECK-NEXT: [[FIELD_U4:@[0-9]+]] = private unnamed_addr constant [25 x i8] c"    unsigned int a = %u\0A\00", align 1
-// CHECK-NEXT: [[END_STRUCT_U4:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_STR_U4:@[0-9]+]] = private unnamed_addr constant [12 x i8] c"struct U4A \00", align 1
+// CHECK-NEXT: [[STRUCT_L_BRACE_U4:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"{\0A\00", align 1
+// CHECK-NEXT: [[FIELD_U4:@[0-9]+]] = private unnamed_addr constant [22 x i8] c"    unsigned int a = \00", align 1
+// CHECK-NEXT: [[FORMAT_U4:@[0-9]+]] = private unnamed_addr constant [4 x i8] c"%u\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_R_BRACE_U4:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
 
 // CHECK: @__const.unit5.a = private unnamed_addr constant %struct.U5A { i64 12 }, align 8
-// CHECK-NEXT: [[STRUCT_STR_U5:@[0-9]+]] = private unnamed_addr constant [14 x i8] c"struct U5A {\0A\00", align 1
-// CHECK-NEXT: [[FIELD_U5:@[0-9]+]] = private unnamed_addr constant [18 x i8] c"    long a = %ld\0A\00", align 1
-// CHECK-NEXT: [[END_STRUCT_U5:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_STR_U5:@[0-9]+]] = private unnamed_addr constant [12 x i8] c"struct U5A \00", align 1
+// CHECK-NEXT: [[STRUCT_L_BRACE_U5:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"{\0A\00", align 1
+// CHECK-NEXT: [[FIELD_U5:@[0-9]+]] = private unnamed_addr constant [14 x i8] c"    long a = \00", align 1
+// CHECK-NEXT: [[FORMAT_U5:@[0-9]+]] = private unnamed_addr constant [5 x i8] c"%ld\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_R_BRACE_U5:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
 
 // CHECK: @__const.unit6.a = private unnamed_addr constant %struct.U6A { i64 12 }, align 8
-// CHECK-NEXT: [[STRUCT_STR_U6:@[0-9]+]] = private unnamed_addr constant [14 x i8] c"struct U6A {\0A\00", align 1
-// CHECK-NEXT: [[FIELD_U6:@[0-9]+]] = private unnamed_addr constant [27 x i8] c"    unsigned long a = %lu\0A\00", align 1
-// CHECK-NEXT: [[END_STRUCT_U6:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_STR_U6:@[0-9]+]] = private unnamed_addr constant [12 x i8] c"struct U6A \00", align 1
+// CHECK-NEXT: [[STRUCT_L_BRACE_U6:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"{\0A\00", align 1
+// CHECK-NEXT: [[FIELD_U6:@[0-9]+]] = private unnamed_addr constant [23 x i8] c"    unsigned long a = \00", align 1
+// CHECK-NEXT: [[FORMAT_U6:@[0-9]+]] = private unnamed_addr constant [5 x i8] c"%lu\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_R_BRACE_U6:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
 
 // CHECK: @__const.unit7.a = private unnamed_addr constant %struct.U7A { i64 12 }, align 8
-// CHECK-NEXT: [[STRUCT_STR_U7:@[0-9]+]] = private unnamed_addr constant [14 x i8] c"struct U7A {\0A\00", align 1
-// CHECK-NEXT: [[FIELD_U7:@[0-9]+]] = private unnamed_addr constant [24 x i8] c"    long long a = %lld\0A\00", align 1
-// CHECK-NEXT: [[END_STRUCT_U7:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_STR_U7:@[0-9]+]] = private unnamed_addr constant [12 x i8] c"struct U7A \00", align 1
+// CHECK-NEXT: [[STRUCT_L_BRACE_U7:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"{\0A\00", align 1
+// CHECK-NEXT: [[FIELD_U7:@[0-9]+]] = private unnamed_addr constant [19 x i8] c"    long long a = \00", align 1
+// CHECK-NEXT: [[FORMAT_U7:@[0-9]+]] = private unnamed_addr constant [6 x i8] c"%lld\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_R_BRACE_U7:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
 
 // CHECK: @__const.unit8.a = private unnamed_addr constant %struct.U8A { i64 12 }, align 8
-// CHECK-NEXT: [[STRUCT_STR_U8:@[0-9]+]] = private unnamed_addr constant [14 x i8] c"struct U8A {\0A\00", align 1
-// CHECK-NEXT: [[FIELD_U8:@[0-9]+]] = private unnamed_addr constant [33 x i8] c"    unsigned long long a = %llu\0A\00", align 1
-// CHECK-NEXT: [[END_STRUCT_U8:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_STR_U8:@[0-9]+]] = private unnamed_addr constant [12 x i8] c"struct U8A \00", align 1
+// CHECK-NEXT: [[STRUCT_L_BRACE_U8:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"{\0A\00", align 1
+// CHECK-NEXT: [[FIELD_U8:@[0-9]+]] = private unnamed_addr constant [28 x i8] c"    unsigned long long a = \00", align 1
+// CHECK-NEXT: [[FORMAT_U8:@[0-9]+]] = private unnamed_addr constant [6 x i8] c"%llu\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_R_BRACE_U8:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
 
 // CHECK: @__const.unit9.a = private unnamed_addr constant %struct.U9A { i8 97 }, align 1
-// CHECK-NEXT: [[STRUCT_STR_U9:@[0-9]+]] = private unnamed_addr constant [14 x i8] c"struct U9A {\0A\00", align 1
-// CHECK-NEXT: [[FIELD_U9:@[0-9]+]] = private unnamed_addr constant [17 x i8] c"    char a = %c\0A\00", align 1
-// CHECK-NEXT: [[END_STRUCT_U9:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_STR_U9:@[0-9]+]] = private unnamed_addr constant [12 x i8] c"struct U9A \00", align 1
+// CHECK-NEXT: [[STRUCT_L_BRACE_U9:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"{\0A\00", align 1
+// CHECK-NEXT: [[FIELD_U9:@[0-9]+]] = private unnamed_addr constant [14 x i8] c"    char a = \00", align 1
+// CHECK-NEXT: [[FORMAT_U9:@[0-9]+]] = private unnamed_addr constant [4 x i8] c"%c\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_R_BRACE_U9:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
 
 // CHECK: @.str = private unnamed_addr constant [4 x i8] c"LSE\00", align 1
 // CHECK: @__const.unit10.a = private unnamed_addr constant %struct.U10A { i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0) }, align 8
-// CHECK-NEXT: [[STRUCT_STR_U10:@[0-9]+]] = private unnamed_addr constant [15 x i8] c"struct U10A {\0A\00", align 1
-// CHECK-NEXT: [[FIELD_U10:@[0-9]+]] = private unnamed_addr constant [19 x i8] c"    char * a = %s\0A\00", align 1
-// CHECK-NEXT: [[END_STRUCT_U10:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_STR_U10:@[0-9]+]] = private unnamed_addr constant [13 x i8] c"struct U10A \00", align 1
+// CHECK-NEXT: [[STRUCT_L_BRACE_U10:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"{\0A\00", align 1
+// CHECK-NEXT: [[FIELD_U10:@[0-9]+]] = private unnamed_addr constant [16 x i8] c"    char * a = \00", align 1
+// CHECK-NEXT: [[FORMAT_U10:@[0-9]+]] = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_R_BRACE_U10:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
 
 // CHECK: @__const.unit11.a = private unnamed_addr constant %struct.U11A { i8* inttoptr (i64 305419896 to i8*) }, align 8
-// CHECK-NEXT: [[STRUCT_STR_U11:@[0-9]+]] = private unnamed_addr constant [15 x i8] c"struct U11A {\0A\00", align 1
-// CHECK-NEXT: [[FIELD_U11:@[0-9]+]] = private unnamed_addr constant [19 x i8] c"    void * a = %p\0A\00", align 1
-// CHECK-NEXT: [[END_STRUCT_U11:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_STR_U11:@[0-9]+]] = private unnamed_addr constant [13 x i8] c"struct U11A \00", align 1
+// CHECK-NEXT: [[STRUCT_L_BRACE_U11:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"{\0A\00", align 1
+// CHECK-NEXT: [[FIELD_U11:@[0-9]+]] = private unnamed_addr constant [16 x i8] c"    void * a = \00", align 1
+// CHECK-NEXT: [[FORMAT_U11:@[0-9]+]] = private unnamed_addr constant [4 x i8] c"%p\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_R_BRACE_U11:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
 
 // CHECK: @__const.unit12.a = private unnamed_addr constant %struct.U12A { i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0) }, align 8
-// CHECK-NEXT: [[STRUCT_STR_U12:@[0-9]+]] = private unnamed_addr constant [15 x i8] c"struct U12A {\0A\00", align 1
-// CHECK-NEXT: [[FIELD_U12:@[0-9]+]] = private unnamed_addr constant [25 x i8] c"    const char * a = %s\0A\00", align 1
-// CHECK-NEXT: [[END_STRUCT_U12:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_STR_U12:@[0-9]+]] = private unnamed_addr constant [13 x i8] c"struct U12A \00", align 1
+// CHECK-NEXT: [[STRUCT_L_BRACE_U12:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"{\0A\00", align 1
+// CHECK-NEXT: [[FIELD_U12:@[0-9]+]] = private unnamed_addr constant [22 x i8] c"    const char * a = \00", align 1
+// CHECK-NEXT: [[FORMAT_U12:@[0-9]+]] = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_R_BRACE_U12:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
 
 // CHECK: @__const.unit13.a = private unnamed_addr constant %struct.U13A { i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str, i32 0, i32 0) }, align 8
-// CHECK-NEXT: [[STRUCT_STR_U13:@[0-9]+]] = private unnamed_addr constant [15 x i8] c"struct U13A {\0A\00", align 1
-// CHECK-NEXT: [[FIELD_U13:@[0-9]+]] = private unnamed_addr constant [27 x i8] c"    const charstar a = %s\0A\00", align 1
-// CHECK-NEXT: [[END_STRUCT_U13:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_STR_U13:@[0-9]+]] = private unnamed_addr constant [13 x i8] c"struct U13A \00", align 1
+// CHECK-NEXT: [[STRUCT_L_BRACE_U13:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"{\0A\00", align 1
+// CHECK-NEXT: [[FIELD_U13:@[0-9]+]] = private unnamed_addr constant [24 x i8] c"    const charstar a = \00", align 1
+// CHECK-NEXT: [[FORMAT_U13:@[0-9]+]] = private unnamed_addr constant [4 x i8] c"%s\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_R_BRACE_U13:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
 
 // CHECK: @__const.unit14.a = private unnamed_addr constant %struct.U14A { double 0x3FF1F9ACFFA7EB6C }, align 8
-// CHECK-NEXT: [[STRUCT_STR_U14:@[0-9]+]] = private unnamed_addr constant [15 x i8] c"struct U14A {\0A\00", align 1
-// CHECK-NEXT: [[FIELD_U14:@[0-9]+]] = private unnamed_addr constant [19 x i8] c"    double a = %f\0A\00", align 1
-// CHECK-NEXT: [[END_STRUCT_U14:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_STR_U14:@[0-9]+]] = private unnamed_addr constant [13 x i8] c"struct U14A \00", align 1
+// CHECK-NEXT: [[STRUCT_L_BRACE_U14:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"{\0A\00", align 1
+// CHECK-NEXT: [[FIELD_U14:@[0-9]+]] = private unnamed_addr constant [16 x i8] c"    double a = \00", align 1
+// CHECK-NEXT: [[FORMAT_U14:@[0-9]+]] = private unnamed_addr constant [4 x i8] c"%f\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_R_BRACE_U14:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
 
 // CHECK: @__const.unit15.a = private unnamed_addr constant %struct.U15A { [3 x i32] [i32 1, i32 2, i32 3] }, align 4
-// CHECK-NEXT: [[STRUCT_STR_U15:@[0-9]+]] = private unnamed_addr constant [15 x i8] c"struct U15A {\0A\00", align 1
-// CHECK-NEXT: [[FIELD_U15:@[0-9]+]] = private unnamed_addr constant [19 x i8] c"    int[3] a = %p\0A\00", align 1
-// CHECK-NEXT: [[END_STRUCT_U15:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_STR_U15:@[0-9]+]] = private unnamed_addr constant [13 x i8] c"struct U15A \00", align 1
+// CHECK-NEXT: [[STRUCT_L_BRACE_U15:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"{\0A\00", align 1
+// CHECK-NEXT: [[FIELD_U15:@[0-9]+]] = private unnamed_addr constant [16 x i8] c"    int[3] a = \00", align 1
+// CHECK-NEXT: [[FORMAT_U15:@[0-9]+]] = private unnamed_addr constant [4 x i8] c"%p\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_R_BRACE_U15:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
 
 // CHECK: @__const.unit16.a = private unnamed_addr constant %struct.U16A { i8 12 }, align 1
-// CHECK-NEXT: [[STRUCT_STR_U16:@[0-9]+]] = private unnamed_addr constant [15 x i8] c"struct U16A {\0A\00", align 1
-// CHECK-NEXT: [[FIELD_U16:@[0-9]+]] = private unnamed_addr constant [22 x i8] c"    uint8_t a = %hhu\0A\00", align 1
-// CHECK-NEXT: [[END_STRUCT_U16:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_STR_U16:@[0-9]+]] = private unnamed_addr constant [13 x i8] c"struct U16A \00", align 1
+// CHECK-NEXT: [[STRUCT_L_BRACE_U16:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"{\0A\00", align 1
+// CHECK-NEXT: [[FIELD_U16:@[0-9]+]] = private unnamed_addr constant [17 x i8] c"    uint8_t a = \00", align 1
+// CHECK-NEXT: [[FORMAT_U16:@[0-9]+]] = private unnamed_addr constant [6 x i8] c"%hhu\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_R_BRACE_U16:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
 
 // CHECK: @__const.unit17.a = private unnamed_addr constant %struct.U17A { i8 12 }, align 1
-// CHECK-NEXT: [[STRUCT_STR_U17:@[0-9]+]] = private unnamed_addr constant [15 x i8] c"struct U17A {\0A\00", align 1
-// CHECK-NEXT: [[FIELD_U17:@[0-9]+]] = private unnamed_addr constant [21 x i8] c"    int8_t a = %hhd\0A\00", align 1
-// CHECK-NEXT: [[END_STRUCT_U17:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_STR_U17:@[0-9]+]] = private unnamed_addr constant [13 x i8] c"struct U17A \00", align 1
+// CHECK-NEXT: [[STRUCT_L_BRACE_U17:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"{\0A\00", align 1
+// CHECK-NEXT: [[FIELD_U17:@[0-9]+]] = private unnamed_addr constant [16 x i8] c"    int8_t a = \00", align 1
+// CHECK-NEXT: [[FORMAT_U17:@[0-9]+]] = private unnamed_addr constant [6 x i8] c"%hhd\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_R_BRACE_U17:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
 
 // CHECK: @__const.unit18.a = private unnamed_addr constant %struct.U18A { x86_fp80 0xK3FFF8FCD67FD3F5B6000 }, align 16
-// CHECK-NEXT: [[STRUCT_STR_U18:@[0-9]+]] = private unnamed_addr constant [15 x i8] c"struct U18A {\0A\00", align 1
-// CHECK-NEXT: [[FIELD_U18:@[0-9]+]] = private unnamed_addr constant [25 x i8] c"    long double a = %Lf\0A\00", align 1
-// CHECK-NEXT: [[END_STRUCT_U18:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_STR_U18:@[0-9]+]] = private unnamed_addr constant [13 x i8] c"struct U18A \00", align 1
+// CHECK-NEXT: [[STRUCT_L_BRACE_U18:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"{\0A\00", align 1
+// CHECK-NEXT: [[FIELD_U18:@[0-9]+]] = private unnamed_addr constant [21 x i8] c"    long double a = \00", align 1
+// CHECK-NEXT: [[FORMAT_U18:@[0-9]+]] = private unnamed_addr constant [5 x i8] c"%Lf\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_R_BRACE_U18:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
+
+// CHECK: @__const.unit19.a = private unnamed_addr constant %struct.U19B { %struct.U19A { i32 2022 } }, align 4
+// CHECK-NEXT: [[STRUCT_STR_U19:@[0-9]+]] = private unnamed_addr constant [13 x i8] c"struct U19B \00", align 1
+// CHECK-NEXT: [[STRUCT_L_BRACE_U19:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"{\0A\00", align 1
+// CHECK-NEXT: [[FIELD_U19:@[0-9]+]] = private unnamed_addr constant [21 x i8] c"    struct U19A a = \00", align 1
+// CHECK-NEXT: [[NESTED_STRUCT_L_BRACE_U19:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"{\0A\00", align 1
+// CHECK-NEXT: [[NESTED_FIELD_U19:@[0-9]+]] = private unnamed_addr constant [17 x i8] c"        int a = \00", align 1
+// CHECK-NEXT: [[NESTED_FORMAT_U19:@[0-9]+]] = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
+// CHECK-NEXT: [[NESTED_STRUCT_R_BRACE_U19:@[0-9]+]] = private unnamed_addr constant [7 x i8] c"    }\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_R_BRACE_U19:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
+
+// CHECK: @__const.unit20.a = private unnamed_addr constant %struct.U20A { i8 1 }, align 1
+// CHECK-NEXT: [[STRUCT_STR_U20:@[0-9]+]] = private unnamed_addr constant [13 x i8] c"struct U20A \00", align 1
+// CHECK-NEXT: [[STRUCT_L_BRACE_U20:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"{\0A\00", align 1
+// CHECK-NEXT: [[FIELD_U20:@[0-9]+]] = private unnamed_addr constant [15 x i8] c"    _Bool a = \00", align 1
+// CHECK-NEXT: [[FORMAT_U20:@[0-9]+]] = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
+// CHECK-NEXT: [[STRUCT_R_BRACE_U20:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
 
 int printf(const char *fmt, ...) {
     return 0;
@@ -106,11 +159,13 @@ void unit1(void) {
   struct U1A a = {
       .a = 12,
   };
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* [[STRUCT_STR_U1]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* [[STRUCT_STR_U1]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_L_BRACE_U1]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* [[FIELD_U1]], i32 0, i32 0))
   // CHECK: [[RES1:%.*]] = getelementptr inbounds %struct.U1A, %struct.U1A* %a, i32 0, i32 0
   // CHECK: [[LOAD1:%.*]] = load i16, i16* [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([19 x i8], [19 x i8]* [[FIELD_U1]], i32 0, i32 0), i16 [[LOAD1]])
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[END_STRUCT_U1]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* [[FORMAT_U1]], i32 0, i32 0), i16 [[LOAD1]])
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_R_BRACE_U1]], i32 0, i32 0))
   __builtin_dump_struct(&a, &printf);
 }
 
@@ -123,11 +178,13 @@ void unit2(void) {
       .a = 12,
   };
 
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* [[STRUCT_STR_U2]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* [[STRUCT_STR_U2]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_L_BRACE_U2]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([24 x i8], [24 x i8]* [[FIELD_U2]], i32 0, i32 0))
   // CHECK: [[RES1:%.*]] = getelementptr inbounds %struct.U2A, %struct.U2A* %a, i32 0, i32 0
   // CHECK: [[LOAD1:%.*]] = load i16, i16* [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([28 x i8], [28 x i8]* [[FIELD_U2]], i32 0, i32 0), i16 [[LOAD1]])
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[END_STRUCT_U2]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* [[FORMAT_U2]], i32 0, i32 0), i16 [[LOAD1]])
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_R_BRACE_U2]], i32 0, i32 0))
   __builtin_dump_struct(&a, &printf);
 }
 
@@ -140,11 +197,13 @@ void unit3(void) {
       .a = 12,
   };
 
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* [[STRUCT_STR_U3]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* [[STRUCT_STR_U3]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_L_BRACE_U3]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* [[FIELD_U3]], i32 0, i32 0))
   // CHECK: [[RES1:%.*]] = getelementptr inbounds %struct.U3A, %struct.U3A* %a, i32 0, i32 0
   // CHECK: [[LOAD1:%.*]] = load i32, i32* [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([16 x i8], [16 x i8]* [[FIELD_U3]], i32 0, i32 0), i32 [[LOAD1]])
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[END_STRUCT_U3]], i32 0, i32 0)
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* [[FORMAT_U3]], i32 0, i32 0), i32 [[LOAD1]])
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_R_BRACE_U3]], i32 0, i32 0)
   __builtin_dump_struct(&a, &printf);
 }
 
@@ -157,11 +216,13 @@ void unit4(void) {
       .a = 12,
   };
 
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* [[STRUCT_STR_U4]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* [[STRUCT_STR_U4]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_L_BRACE_U4]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([22 x i8], [22 x i8]* [[FIELD_U4]], i32 0, i32 0))
   // CHECK: [[RES1:%.*]] = getelementptr inbounds %struct.U4A, %struct.U4A* %a, i32 0, i32 0
   // CHECK: [[LOAD1:%.*]] = load i32, i32* [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([25 x i8], [25 x i8]* [[FIELD_U4]], i32 0, i32 0), i32 [[LOAD1]])
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[END_STRUCT_U4]], i32 0, i32 0)
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* [[FORMAT_U4]], i32 0, i32 0), i32 [[LOAD1]])
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_R_BRACE_U4]], i32 0, i32 0)
   __builtin_dump_struct(&a, &printf);
 }
 
@@ -174,11 +235,13 @@ void unit5(void) {
       .a = 12,
   };
 
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* [[STRUCT_STR_U5]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* [[STRUCT_STR_U5]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_L_BRACE_U5]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* [[FIELD_U5]], i32 0, i32 0))
   // CHECK: [[RES1:%.*]] = getelementptr inbounds %struct.U5A, %struct.U5A* %a, i32 0, i32 0
   // CHECK: [[LOAD1:%.*]] = load i64, i64* [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* [[FIELD_U5]], i32 0, i32 0), i64 [[LOAD1]])
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[END_STRUCT_U5]], i32 0, i32 0)
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* [[FORMAT_U5]], i32 0, i32 0), i64 [[LOAD1]])
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_R_BRACE_U5]], i32 0, i32 0)
   __builtin_dump_struct(&a, &printf);
 }
 
@@ -191,11 +254,13 @@ void unit6(void) {
       .a = 12,
   };
 
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* [[STRUCT_STR_U6]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* [[STRUCT_STR_U6]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_L_BRACE_U6]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([23 x i8], [23 x i8]* [[FIELD_U6]], i32 0, i32 0))
   // CHECK: [[RES1:%.*]] = getelementptr inbounds %struct.U6A, %struct.U6A* %a, i32 0, i32 0
   // CHECK: [[LOAD1:%.*]] = load i64, i64* [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([27 x i8], [27 x i8]* [[FIELD_U6]], i32 0, i32 0), i64 [[LOAD1]])
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[END_STRUCT_U6]], i32 0, i32 0)
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* [[FORMAT_U6]], i32 0, i32 0), i64 [[LOAD1]])
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_R_BRACE_U6]], i32 0, i32 0)
   __builtin_dump_struct(&a, &printf);
 }
 
@@ -208,11 +273,13 @@ void unit7(void) {
       .a = 12,
   };
 
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* [[STRUCT_STR_U7]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* [[STRUCT_STR_U7]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_L_BRACE_U7]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([19 x i8], [19 x i8]* [[FIELD_U7]], i32 0, i32 0))
   // CHECK: [[RES1:%.*]] = getelementptr inbounds %struct.U7A, %struct.U7A* %a, i32 0, i32 0
   // CHECK: [[LOAD1:%.*]] = load i64, i64* [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([24 x i8], [24 x i8]* [[FIELD_U7]], i32 0, i32 0), i64 [[LOAD1]])
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[END_STRUCT_U7]], i32 0, i32 0)
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* [[FORMAT_U7]], i32 0, i32 0), i64 [[LOAD1]])
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_R_BRACE_U7]], i32 0, i32 0)
   __builtin_dump_struct(&a, &printf);
 }
 
@@ -225,11 +292,13 @@ void unit8(void) {
       .a = 12,
   };
 
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* [[STRUCT_STR_U8]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* [[STRUCT_STR_U8]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_L_BRACE_U8]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([28 x i8], [28 x i8]* [[FIELD_U8]], i32 0, i32 0))
   // CHECK: [[RES1:%.*]] = getelementptr inbounds %struct.U8A, %struct.U8A* %a, i32 0, i32 0
   // CHECK: [[LOAD1:%.*]] = load i64, i64* [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([33 x i8], [33 x i8]* [[FIELD_U8]], i32 0, i32 0), i64 [[LOAD1]])
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[END_STRUCT_U8]], i32 0, i32 0)
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* [[FORMAT_U8]], i32 0, i32 0), i64 [[LOAD1]])
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_R_BRACE_U8]], i32 0, i32 0)
   __builtin_dump_struct(&a, &printf);
 }
 
@@ -242,11 +311,13 @@ void unit9(void) {
       .a = 'a',
   };
 
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* [[STRUCT_STR_U9]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* [[STRUCT_STR_U9]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_L_BRACE_U9]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* [[FIELD_U9]], i32 0, i32 0))
   // CHECK: [[RES1:%.*]] = getelementptr inbounds %struct.U9A, %struct.U9A* %a, i32 0, i32 0
   // CHECK: [[LOAD1:%.*]] = load i8, i8* [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([17 x i8], [17 x i8]* [[FIELD_U9]], i32 0, i32 0), i8 [[LOAD1]])
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[END_STRUCT_U9]], i32 0, i32 0)
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* [[FORMAT_U9]], i32 0, i32 0), i8 [[LOAD1]])
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_R_BRACE_U9]], i32 0, i32 0)
   __builtin_dump_struct(&a, &printf);
 }
 
@@ -259,11 +330,13 @@ void unit10(void) {
       .a = "LSE",
   };
 
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* [[STRUCT_STR_U10]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* [[STRUCT_STR_U10]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_L_BRACE_U10]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([16 x i8], [16 x i8]* [[FIELD_U10]], i32 0, i32 0))
   // CHECK: [[RES1:%.*]] = getelementptr inbounds %struct.U10A, %struct.U10A* %a, i32 0, i32 0
   // CHECK: [[LOAD1:%.*]] = load i8*, i8** [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([19 x i8], [19 x i8]* [[FIELD_U10]], i32 0, i32 0), i8* [[LOAD1]])
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[END_STRUCT_U10]], i32 0, i32 0)
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* [[FORMAT_U10]], i32 0, i32 0), i8* [[LOAD1]])
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_R_BRACE_U10]], i32 0, i32 0)
   __builtin_dump_struct(&a, &printf);
 }
 
@@ -276,11 +349,13 @@ void unit11(void) {
       .a = (void *)0x12345678,
   };
 
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* [[STRUCT_STR_U11]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* [[STRUCT_STR_U11]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_L_BRACE_U11]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([16 x i8], [16 x i8]* [[FIELD_U11]], i32 0, i32 0))
   // CHECK: [[RES1:%.*]] = getelementptr inbounds %struct.U11A, %struct.U11A* %a, i32 0, i32 0
   // CHECK: [[LOAD1:%.*]] = load i8*, i8** [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([19 x i8], [19 x i8]* [[FIELD_U11]], i32 0, i32 0), i8* [[LOAD1]])
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[END_STRUCT_U11]], i32 0, i32 0)
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* [[FORMAT_U11]], i32 0, i32 0), i8* [[LOAD1]])
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_R_BRACE_U11]], i32 0, i32 0)
   __builtin_dump_struct(&a, &printf);
 }
 
@@ -293,11 +368,13 @@ void unit12(void) {
       .a = "LSE",
   };
 
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* [[STRUCT_STR_U12]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* [[STRUCT_STR_U12]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_L_BRACE_U12]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([22 x i8], [22 x i8]* [[FIELD_U12]], i32 0, i32 0))
   // CHECK: [[RES1:%.*]] = getelementptr inbounds %struct.U12A, %struct.U12A* %a, i32 0, i32 0
   // CHECK: [[LOAD1:%.*]] = load i8*, i8** [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([25 x i8], [25 x i8]* [[FIELD_U12]], i32 0, i32 0), i8* [[LOAD1]])
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[END_STRUCT_U12]], i32 0, i32 0)
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* [[FORMAT_U12]], i32 0, i32 0), i8* [[LOAD1]])
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_R_BRACE_U12]], i32 0, i32 0)
   __builtin_dump_struct(&a, &printf);
 }
 
@@ -311,11 +388,13 @@ void unit13(void) {
       .a = "LSE",
   };
 
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* [[STRUCT_STR_U13]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* [[STRUCT_STR_U13]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_L_BRACE_U13]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([24 x i8], [24 x i8]* [[FIELD_U13]], i32 0, i32 0))
   // CHECK: [[RES1:%.*]] = getelementptr inbounds %struct.U13A, %struct.U13A* %a, i32 0, i32 0
   // CHECK: [[LOAD1:%.*]] = load i8*, i8** [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([27 x i8], [27 x i8]* [[FIELD_U13]], i32 0, i32 0), i8* [[LOAD1]])
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[END_STRUCT_U13]], i32 0, i32 0)
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* [[FORMAT_U13]], i32 0, i32 0), i8* [[LOAD1]])
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_R_BRACE_U13]], i32 0, i32 0)
   __builtin_dump_struct(&a, &printf);
 }
 
@@ -328,11 +407,13 @@ void unit14(void) {
       .a = 1.123456,
   };
 
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* [[STRUCT_STR_U14]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* [[STRUCT_STR_U14]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_L_BRACE_U14]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([16 x i8], [16 x i8]* [[FIELD_U14]], i32 0, i32 0))
   // CHECK: [[RES1:%.*]] = getelementptr inbounds %struct.U14A, %struct.U14A* %a, i32 0, i32 0
   // CHECK: [[LOAD1:%.*]] = load double, double* [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([19 x i8], [19 x i8]* [[FIELD_U14]], i32 0, i32 0), double [[LOAD1]])
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[END_STRUCT_U14]], i32 0, i32 0)
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* [[FORMAT_U14]], i32 0, i32 0), double [[LOAD1]])
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_R_BRACE_U14]], i32 0, i32 0)
   __builtin_dump_struct(&a, &printf);
 }
 
@@ -345,11 +426,13 @@ void unit15(void) {
       .a = {1, 2, 3},
   };
 
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* [[STRUCT_STR_U15]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* [[STRUCT_STR_U15]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_L_BRACE_U15]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([16 x i8], [16 x i8]* [[FIELD_U15]], i32 0, i32 0))
   // CHECK: [[RES1:%.*]] = getelementptr inbounds %struct.U15A, %struct.U15A* %a, i32 0, i32 0
   // CHECK: [[LOAD1:%.*]] = load [3 x i32], [3 x i32]* [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([19 x i8], [19 x i8]* [[FIELD_U15]], i32 0, i32 0), [3 x i32] [[LOAD1]])
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[END_STRUCT_U15]], i32 0, i32 0)
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* [[FORMAT_U15]], i32 0, i32 0), [3 x i32] [[LOAD1]])
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_R_BRACE_U15]], i32 0, i32 0)
   __builtin_dump_struct(&a, &printf);
 }
 
@@ -362,11 +445,13 @@ void unit16(void) {
       .a = 12,
   };
 
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* [[STRUCT_STR_U16]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* [[STRUCT_STR_U16]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_L_BRACE_U16]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([17 x i8], [17 x i8]* [[FIELD_U16]], i32 0, i32 0))
   // CHECK: [[RES1:%.*]] = getelementptr inbounds %struct.U16A, %struct.U16A* %a, i32 0, i32 0
   // CHECK: [[LOAD1:%.*]] = load i8, i8* [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([22 x i8], [22 x i8]* [[FIELD_U16]], i32 0, i32 0), i8 [[LOAD1]])
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[END_STRUCT_U16]], i32 0, i32 0)
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* [[FORMAT_U16]], i32 0, i32 0), i8 [[LOAD1]])
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_R_BRACE_U16]], i32 0, i32 0)
   __builtin_dump_struct(&a, &printf);
 }
 
@@ -379,11 +464,13 @@ void unit17(void) {
       .a = 12,
   };
 
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* [[STRUCT_STR_U17]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* [[STRUCT_STR_U17]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_L_BRACE_U17]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([16 x i8], [16 x i8]* [[FIELD_U17]], i32 0, i32 0))
   // CHECK: [[RES1:%.*]] = getelementptr inbounds %struct.U17A, %struct.U17A* %a, i32 0, i32 0
   // CHECK: [[LOAD1:%.*]] = load i8, i8* [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([21 x i8], [21 x i8]* [[FIELD_U17]], i32 0, i32 0), i8 [[LOAD1]])
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[END_STRUCT_U17]], i32 0, i32 0)
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* [[FORMAT_U17]], i32 0, i32 0), i8 [[LOAD1]])
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_R_BRACE_U17]], i32 0, i32 0)
   __builtin_dump_struct(&a, &printf);
 }
 
@@ -396,11 +483,61 @@ void unit18(void) {
       .a = 1.123456,
   };
 
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* [[STRUCT_STR_U18]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* [[STRUCT_STR_U18]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_L_BRACE_U18]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([21 x i8], [21 x i8]* [[FIELD_U18]], i32 0, i32 0))
   // CHECK: [[RES1:%.*]] = getelementptr inbounds %struct.U18A, %struct.U18A* %a, i32 0, i32 0
   // CHECK: [[LOAD1:%.*]] = load x86_fp80, x86_fp80* [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([25 x i8], [25 x i8]* [[FIELD_U18]], i32 0, i32 0), x86_fp80 [[LOAD1]])
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[END_STRUCT_U18]], i32 0, i32 0)
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([5 x i8], [5 x i8]* [[FORMAT_U18]], i32 0, i32 0), x86_fp80 [[LOAD1]])
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_R_BRACE_U18]], i32 0, i32 0)
+  __builtin_dump_struct(&a, &printf);
+}
+
+void unit19(void) {
+
+  struct U19A {
+    int a;
+  };
+
+  struct U19B {
+    struct U19A a;
+  };
+
+  struct U19B a = {
+    .a.a = 2022
+  };
+
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* [[STRUCT_STR_U19]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_L_BRACE_U19]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([21 x i8], [21 x i8]* [[FIELD_U19]], i32 0, i32 0))
+  // CHECK: [[RES1:%.*]] = getelementptr inbounds %struct.U19B, %struct.U19B* %a, i32 0, i32 0
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[NESTED_STRUCT_L_BRACE_U19]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([17 x i8], [17 x i8]* [[NESTED_FIELD_U19]], i32 0, i32 0))
+  // CHECK: [[RES2:%.*]] = getelementptr inbounds %struct.U19A, %struct.U19A* [[RES1]], i32 0, i32 0
+  // CHECK: [[LOAD2:%.*]] = load i32, i32* [[RES2]],
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* [[NESTED_FORMAT_U19]], i32 0, i32 0), i32 [[LOAD2]])
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* [[NESTED_STRUCT_R_BRACE_U19]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_R_BRACE_U19]], i32 0, i32 0))
+  __builtin_dump_struct(&a, &printf);
+}
+
+void unit20(void) {
+  struct U20A {
+    _Bool a;
+  };
+
+  struct U20A a = {
+    .a = 1,
+  };
+
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* [[STRUCT_STR_U20]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_L_BRACE_U20]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* [[FIELD_U20]], i32 0, i32 0))
+  // CHECK: [[RES1:%.*]] = getelementptr inbounds %struct.U20A, %struct.U20A* %a, i32 0, i32 0
+  // CHECK: [[LOAD1:%.*]] = load i8, i8* [[RES1]],
+  // CHECK: [[TOBOOL:%.*]] = trunc i8 [[LOAD1]] to i1
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* [[FORMAT_U20]], i32 0, i32 0), i1 [[TOBOOL]])
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[STRUCT_R_BRACE_U20]], i32 0, i32 0)
   __builtin_dump_struct(&a, &printf);
 }
 
@@ -415,10 +552,13 @@ void test1(void) {
       .b = "LSE",
   };
 
+  // CHECK: call i32 (i8*, ...) @printf(
+  // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: [[RES1:%.*]] = getelementptr inbounds %struct.T1A, %struct.T1A* %a, i32 0, i32 0
   // CHECK: [[LOAD1:%.*]] = load i32, i32* [[RES1]],
   // CHECK: call i32 (i8*, ...) @printf({{.*}}, i32 [[LOAD1]])
+  // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: [[RES2:%.*]] = getelementptr inbounds %struct.T1A, %struct.T1A* %a, i32 0, i32 1
   // CHECK: [[LOAD2:%.*]] = load i8*, i8** [[RES2]],
   // CHECK: call i32 (i8*, ...) @printf({{.*}}, i8* [[LOAD2]])
@@ -443,16 +583,21 @@ void test2(void) {
       }
   };
 
+  // CHECK: call i32 (i8*, ...) @printf(
+  // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: [[RES1:%.*]] = getelementptr inbounds %struct.T2B, %struct.T2B* %b, i32 0, i32 0
   // CHECK: [[LOAD1:%.*]] = load i32, i32* [[RES1]],
   // CHECK: call i32 (i8*, ...) @printf({{.*}}, i32 [[LOAD1]])
+  // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: [[NESTED_STRUCT:%.*]] = getelementptr inbounds %struct.T2B, %struct.T2B* %b, i32 0, i32 1
   // CHECK: call i32 (i8*, ...) @printf(
+  // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: [[RES2:%.*]] = getelementptr inbounds %struct.T2A, %struct.T2A* [[NESTED_STRUCT]], i32 0, i32 0
   // CHECK: [[LOAD2:%.*]] = load i32, i32* [[RES2]],
   // CHECK: call i32 (i8*, ...) @printf({{.*}}, i32 [[LOAD2]])
   // CHECK: call i32 (i8*, ...) @printf(
+  // CHECK: call i32 (i8*, ...) @printf(
   __builtin_dump_struct(&b, &printf);
 }
 
@@ -468,12 +613,16 @@ void test3(void) {
       .a = 42,
   };
 
+  // CHECK: call i32 (i8*, ...) @printf(
+  // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: [[RES1:%.*]] = getelementptr inbounds %struct.T3A, %struct.T3A* %a, i32 0, i32 0
   // CHECK: call i32 (i8*, ...) @printf(
+  // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: [[BC1:%.*]] = bitcast %union.anon* [[RES1]] to i32*
   // CHECK: [[LOAD1:%.*]] = load i32, i32* [[BC1]],
   // CHECK: call i32 (i8*, ...) @printf({{.*}}, i32 [[LOAD1]])
+  // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: [[BC2:%.*]] = bitcast %union.anon* [[RES1]] to [4 x i8]*
   // CHECK: [[LOAD2:%.*]] = load [4 x i8], [4 x i8]* [[BC2]],
   // CHECK: call i32 (i8*, ...) @printf({{.*}}, [4 x i8] [[LOAD2]])
@@ -498,17 +647,23 @@ void test4(void) {
       .a = (void *)0x12345678,
   };
 
+  // CHECK: call i32 (i8*, ...) @printf(
+  // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: [[RES1:%.*]] = getelementptr inbounds %struct.T4A, %struct.T4A* %a, i32 0, i32 0
   // CHECK: call i32 (i8*, ...) @printf(
+  // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: [[BC1:%.*]] = bitcast %union.anon.0* [[RES1]] to %struct.anon*
   // CHECK: call i32 (i8*, ...) @printf(
+  // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: [[RES2:%.*]] = getelementptr inbounds %struct.anon, %struct.anon* [[BC1]], i32 0, i32 0
   // CHECK: [[LOAD1:%.*]] = load i8*, i8** [[RES2]],
   // CHECK: call i32 (i8*, ...) @printf({{.*}}, i8* [[LOAD1]])
   // CHECK: call i32 (i8*, ...) @printf(
+  // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: [[BC2:%.*]] = bitcast %union.anon.0* [[RES1]] to %struct.anon.1*
   // CHECK: call i32 (i8*, ...) @printf(
+  // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: [[RES3:%.*]] = getelementptr inbounds %struct.anon.1, %struct.anon.1* [[BC2]], i32 0, i32 0
   // CHECK: [[LOAD2:%.*]] = load i64, i64* [[RES3]],
   // CHECK: call i32 (i8*, ...) @printf({{.*}}, i64 [[LOAD2]])
@@ -527,12 +682,14 @@ void test5(void) {
     .a = 0,
   };
 
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* {{.*}}, i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(
+  // CHECK: call i32 (i8*, ...) @printf(
+  // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: [[BC1:%.*]] = bitcast %struct.T5A* %a to i8*
   // CHECK: [[LOAD1:%.*]] = load i8, i8* [[BC1]],
   // CHECK: [[CLEAR1:%.*]] = and i8 [[LOAD1]], 1
   // CHECK: [[CAST1:%.*]] = zext i8 [[CLEAR1]] to i32
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([29 x i8], [29 x i8]* {{.*}}, i32 0, i32 0), i32 [[CAST1]])
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ({{.*}}, i32 [[CAST1]])
   // CHECK: call i32 (i8*, ...) @printf(
   __builtin_dump_struct(&a, &printf);
 }
@@ -550,24 +707,28 @@ void test6(void) {
     .c = 1,
   };
 
+  // CHECK: call i32 (i8*, ...) @printf(
+  // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: [[BC1:%.*]] = bitcast %struct.T6A* %a to i8*
   // CHECK: [[LOAD1:%.*]] = load i8, i8* [[BC1]],
   // CHECK: [[CLEAR1:%.*]] = and i8 [[LOAD1]], 1
   // CHECK: [[CAST1:%.*]] = zext i8 [[CLEAR1]] to i32
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([29 x i8], [29 x i8]* {{.*}}, i32 0, i32 0), i32 [[CAST1]])
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ({{.*}}, i32 [[CAST1]])
+  // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: [[BC2:%.*]] = bitcast %struct.T6A* %a to i8*
   // CHECK: [[LOAD2:%.*]] = load i8, i8* [[BC2]], align 4
   // CHECK: [[LSHR2:%.*]] = lshr i8 [[LOAD2]], 1
   // CHECK: [[CLEAR2:%.*]] = and i8 [[LSHR2]], 1
   // CHECK: [[CAST2:%.*]] = zext i8 [[CLEAR2]] to i32
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([29 x i8], [29 x i8]* {{.*}}, i32 0, i32 0), i32 [[CAST2]])
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ({{.*}}, i32 [[CAST2]])
+  // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: [[BC3:%.*]] = bitcast %struct.T6A* %a to i8*
   // CHECK: [[LOAD3:%.*]] = load i8, i8* [[BC3]], align 4
   // CHECK: [[LSHR3:%.*]] = lshr i8 [[LOAD3]], 2
   // CHECK: [[CLEAR3:%.*]] = and i8 [[LSHR3]], 1
   // CHECK: [[CAST3:%.*]] = zext i8 [[CLEAR3]] to i32
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([29 x i8], [29 x i8]* {{.*}}, i32 0, i32 0), i32 [[CAST3]])
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ({{.*}}, i32 [[CAST3]])
   // CHECK: call i32 (i8*, ...) @printf(
   __builtin_dump_struct(&a, &printf);
 }
@@ -588,20 +749,24 @@ void test7(void) {
     .b = 1,
   };
 
+  // CHECK: call i32 (i8*, ...) @printf(
+  // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: [[RES1:%.*]] = getelementptr inbounds %struct.T7B, %struct.T7B* %a, i32 0, i32 0
   // CHECK: call i32 (i8*, ...) @printf(
+  // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: [[BC1:%.*]] = bitcast %struct.T7A* [[RES1]] to i8*
   // CHECK: [[LOAD1:%.*]] = load i8, i8* [[BC1]],
   // CHECK: [[CLEAR1:%.*]] = and i8 [[LOAD1]], 1
   // CHECK: [[CAST1:%.*]] = zext i8 [[CLEAR1]] to i32
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([33 x i8], [33 x i8]* {{.*}}, i32 0, i32 0), i32 [[CAST1]])
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ({{.*}}, i32 [[CAST1]])
+  // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: [[RES2:%.*]] = getelementptr inbounds %struct.T7B, %struct.T7B* %a, i32 0, i32 1
   // CHECK: [[LOAD2:%.*]] = load i8, i8* [[RES2]], align 4
   // CHECK: [[CLEAR2:%.*]] = and i8 [[LOAD2]], 1
   // CHECK: [[CAST2:%.*]] = zext i8 [[CLEAR2]] to i32
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([29 x i8], [29 x i8]* {{.*}}, i32 0, i32 0), i32 [[CAST2]])
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ({{.*}}, i32 [[CAST2]])
   // CHECK: call i32 (i8*, ...) @printf(
    __builtin_dump_struct(&a, &printf);
 }
@@ -618,22 +783,27 @@ void test8(void) {
     .b = 2022,
   };
 
+  // CHECK: call i32 (i8*, ...) @printf(
+  // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: [[BC1:%.*]] = bitcast %struct.T8A* %a to i8*
   // CHECK: [[LOAD1:%.*]] = load i8, i8* [[BC1]],
   // CHECK: [[CLEAR1:%.*]] = and i8 [[LOAD1]], 1
   // CHECK: [[CAST1:%.*]] = zext i8 [[CLEAR1]] to i32
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([29 x i8], [29 x i8]* {{.*}}, i32 0, i32 0), i32 [[CAST1]])
+  // CHECK: call i32 (i8*, ...) @printf({{.*}}, i32 [[CAST1]])
+  // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: [[BC2:%.*]] = bitcast %struct.T8A* %a to i8*
   // CHECK: [[LOAD2:%.*]] = load i8, i8* [[BC2]],
   // CHECK: [[LSHR2:%.*]] = lshr i8 [[LOAD2]], 1
   // CHECK: [[CLEAR2:%.*]] = and i8 [[LSHR2]], 7
   // CHECK: [[CAST2:%.*]] = zext i8 [[CLEAR2]] to i32
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([27 x i8], [27 x i8]* {{.*}}, i32 0, i32 0), i32 [[CAST2]])
+  // CHECK: call i32 (i8*, ...) @printf({{.*}}, i32 0, i32 0), i32 [[CAST2]])
+  // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: [[RES3:%.*]] = getelementptr inbounds %struct.T8A, %struct.T8A* %a, i32 0, i32 1
   // CHECK: [[LOAD3:%.*]] = load i32, i32* [[RES3]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([25 x i8], [25 x i8]* {{.*}}, i32 0, i32 0), i32 [[LOAD3]])
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ({{.*}}, i32 [[LOAD3]])
   // CHECK: call i32 (i8*, ...) @printf(
   __builtin_dump_struct(&a, &printf);
 }
+


        


More information about the cfe-commits mailing list