yihanaa updated this revision to Diff 418895.
yihanaa added a comment.

Remove unnecessary code format


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D122662/new/

https://reviews.llvm.org/D122662

Files:
  clang/docs/LanguageExtensions.rst
  clang/docs/ReleaseNotes.rst
  clang/lib/CodeGen/CGBuiltin.cpp
  clang/test/CodeGen/dump-struct-builtin.c

Index: clang/test/CodeGen/dump-struct-builtin.c
===================================================================
--- clang/test/CodeGen/dump-struct-builtin.c
+++ clang/test/CodeGen/dump-struct-builtin.c
@@ -5,95 +5,111 @@
 
 // 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 [15 x i8] c"short a = %hd\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: @__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 [24 x i8] c"unsigned short a = %hu\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: @__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 [12 x i8] c"int a = %d\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: @__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 [21 x i8] c"unsigned int a = %u\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: @__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 [14 x i8] c"long a = %ld\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: @__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 [23 x i8] c"unsigned long a = %lu\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: @__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 [20 x i8] c"long long a = %lld\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: @__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 [29 x i8] c"unsigned long long a = %llu\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: @__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 [13 x i8] c"char a = %c\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: @.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 [15 x i8] c"char * a = %s\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: @__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 [15 x i8] c"void * a = %p\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: @__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 [21 x i8] c"const char * a = %s\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: @__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 [23 x i8] c"const charstar a = %s\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: @__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 [15 x i8] c"double a = %f\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: @__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 [15 x i8] c"int[3] a = %p\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: [[ARRAY_L_SQUARE_U15:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"[\0A\00", align 1
+// CHECK-NEXT: [[ARRAY_INDEX_U15:@[0-9]+]] = private unnamed_addr constant [17 x i8] c"        [%ld] = \00", align 1
+// CHECK-NEXT: [[ARRAY_ELEMENT_U15:@[0-9]+]] = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
+// CHECK-NEXT: [[ARRAY_R_SQUARE_U15:@[0-9]+]] = private unnamed_addr constant [7 x i8] c"    ]\0A\00", align 1
 // CHECK-NEXT: [[END_STRUCT_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 [18 x i8] c"uint8_t a = %hhu\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: @__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 [17 x i8] c"int8_t a = %hhd\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: @__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 [21 x i8] c"long double a = %Lf\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: @__const.unit19.a = private unnamed_addr constant %struct.T19A { {{.*}} }, align 4
+// CHECK-NEXT: [[STRUCT_STR_U19:@[0-9]+]] = private unnamed_addr constant [15 x i8] c"struct T19A {\0A\00", align 1
+// CHECK-NEXT: [[FIELD_U19:@[0-9]+]] = private unnamed_addr constant [19 x i8] c"    int[2][2] b = \00", align 1
+// CHECK-NEXT: [[ARRAY_L_SQUARE_U19:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"[\0A\00", align 1
+// CHECK-NEXT: [[ARRAY_INDEX_U19:@[0-9]+]] = private unnamed_addr constant [17 x i8] c"        [%ld] = \00", align 1
+// CHECK-NEXT: [[ARRAY_L_SQUARE2_U19:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"[\0A\00", align 1
+// CHECK-NEXT: [[ARRAY_INDEX2_U19:@[0-9]+]] = private unnamed_addr constant [21 x i8] c"            [%ld] = \00", align 1
+// CHECK-NEXT: [[ARRAY_ELEMENT_U19:@[0-9]+]] = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
+// CHECK-NEXT: [[ARRAY_R_SQUARE2_U19:@[0-9]+]] = private unnamed_addr constant [11 x i8] c"        ]\0A\00", align 1
+// CHECK-NEXT: [[ARRAY_R_SQUARE_U19:@[0-9]+]] = private unnamed_addr constant [7 x i8] c"    ]\0A\00", align 1
+// CHECK-NEXT: [[END_STRUCT_U19:@[0-9]+]] = private unnamed_addr constant [3 x i8] c"}\0A\00", align 1
+
 int printf(const char *fmt, ...) {
     return 0;
 }
@@ -109,7 +125,7 @@
   // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* [[STRUCT_STR_U1]], i32 0, i32 0))
   // CHECK: [[RES1:%[−a−zA−Z._0-9]+]] = getelementptr inbounds %struct.U1A, %struct.U1A* %a, i32 0, i32 0
   // CHECK: [[LOAD1:%[0-9]+]] = load i16, i16* [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* [[FIELD_U1]], i32 0, i32 0), i16 [[LOAD1]])
+  // 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))
   __builtin_dump_struct(&a, &printf);
 }
@@ -126,7 +142,7 @@
   // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* [[STRUCT_STR_U2]], i32 0, i32 0))
   // CHECK: [[RES1:%[−a−zA−Z._0-9]+]] = getelementptr inbounds %struct.U2A, %struct.U2A* %a, i32 0, i32 0
   // CHECK: [[LOAD1:%[0-9]+]] = load i16, i16* [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([24 x i8], [24 x i8]* [[FIELD_U2]], i32 0, i32 0), i16 [[LOAD1]])
+  // 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))
   __builtin_dump_struct(&a, &printf);
 }
@@ -143,7 +159,7 @@
   // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* [[STRUCT_STR_U3]], i32 0, i32 0))
   // CHECK: [[RES1:%[−a−zA−Z._0-9]+]] = getelementptr inbounds %struct.U3A, %struct.U3A* %a, i32 0, i32 0
   // CHECK: [[LOAD1:%[0-9]+]] = load i32, i32* [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* [[FIELD_U3]], i32 0, i32 0), i32 [[LOAD1]])
+  // 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)
   __builtin_dump_struct(&a, &printf);
 }
@@ -160,7 +176,7 @@
   // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* [[STRUCT_STR_U4]], i32 0, i32 0))
   // CHECK: [[RES1:%[−a−zA−Z._0-9]+]] = getelementptr inbounds %struct.U4A, %struct.U4A* %a, i32 0, i32 0
   // CHECK: [[LOAD1:%[0-9]+]] = load i32, i32* [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([21 x i8], [21 x i8]* [[FIELD_U4]], i32 0, i32 0), i32 [[LOAD1]])
+  // 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)
   __builtin_dump_struct(&a, &printf);
 }
@@ -177,7 +193,7 @@
   // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* [[STRUCT_STR_U5]], i32 0, i32 0))
   // CHECK: [[RES1:%[−a−zA−Z._0-9]+]] = getelementptr inbounds %struct.U5A, %struct.U5A* %a, i32 0, i32 0
   // CHECK: [[LOAD1:%[0-9]+]] = load i64, i64* [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* [[FIELD_U5]], i32 0, i32 0), i64 [[LOAD1]])
+  // 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)
   __builtin_dump_struct(&a, &printf);
 }
@@ -194,7 +210,7 @@
   // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* [[STRUCT_STR_U6]], i32 0, i32 0))
   // CHECK: [[RES1:%[−a−zA−Z._0-9]+]] = getelementptr inbounds %struct.U6A, %struct.U6A* %a, i32 0, i32 0
   // CHECK: [[LOAD1:%[0-9]+]] = load i64, i64* [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([23 x i8], [23 x i8]* [[FIELD_U6]], i32 0, i32 0), i64 [[LOAD1]])
+  // 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)
   __builtin_dump_struct(&a, &printf);
 }
@@ -211,7 +227,7 @@
   // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* [[STRUCT_STR_U7]], i32 0, i32 0))
   // CHECK: [[RES1:%[−a−zA−Z._0-9]+]] = getelementptr inbounds %struct.U7A, %struct.U7A* %a, i32 0, i32 0
   // CHECK: [[LOAD1:%[0-9]+]] = load i64, i64* [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([20 x i8], [20 x i8]* [[FIELD_U7]], i32 0, i32 0), i64 [[LOAD1]])
+  // 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)
   __builtin_dump_struct(&a, &printf);
 }
@@ -228,7 +244,7 @@
   // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* [[STRUCT_STR_U8]], i32 0, i32 0))
   // CHECK: [[RES1:%[−a−zA−Z._0-9]+]] = getelementptr inbounds %struct.U8A, %struct.U8A* %a, i32 0, i32 0
   // CHECK: [[LOAD1:%[0-9]+]] = load i64, i64* [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([29 x i8], [29 x i8]* [[FIELD_U8]], i32 0, i32 0), i64 [[LOAD1]])
+  // 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)
   __builtin_dump_struct(&a, &printf);
 }
@@ -245,7 +261,7 @@
   // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* [[STRUCT_STR_U9]], i32 0, i32 0))
   // CHECK: [[RES1:%[−a−zA−Z._0-9]+]] = getelementptr inbounds %struct.U9A, %struct.U9A* %a, i32 0, i32 0
   // CHECK: [[LOAD1:%[0-9]+]] = load i8, i8* [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* [[FIELD_U9]], i32 0, i32 0), i8 [[LOAD1]])
+  // 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)
   __builtin_dump_struct(&a, &printf);
 }
@@ -262,7 +278,7 @@
   // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* [[STRUCT_STR_U10]], i32 0, i32 0))
   // CHECK: [[RES1:%[−a−zA−Z._0-9]+]] = getelementptr inbounds %struct.U10A, %struct.U10A* %a, i32 0, i32 0
   // CHECK: [[LOAD1:%[0-9]+]] = load i8*, i8** [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* [[FIELD_U10]], i32 0, i32 0), i8* [[LOAD1]])
+  // 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)
   __builtin_dump_struct(&a, &printf);
 }
@@ -279,7 +295,7 @@
   // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* [[STRUCT_STR_U11]], i32 0, i32 0))
   // CHECK: [[RES1:%[−a−zA−Z._0-9]+]] = getelementptr inbounds %struct.U11A, %struct.U11A* %a, i32 0, i32 0
   // CHECK: [[LOAD1:%[0-9]+]] = load i8*, i8** [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* [[FIELD_U11]], i32 0, i32 0), i8* [[LOAD1]])
+  // 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)
   __builtin_dump_struct(&a, &printf);
 }
@@ -294,9 +310,9 @@
   };
 
   // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* [[STRUCT_STR_U12]], i32 0, i32 0))
-  // CHECK: [[RES1:%[−a−zA−Z._0-9]+]] = getelementptr inbounds %struct.U12A, %struct.U12A* %a, i32 0, i32 0
-  // CHECK: [[LOAD1:%[0-9]+]] = load i8*, i8** [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([21 x i8], [21 x i8]* [[FIELD_U12]], i32 0, i32 0), i8* [[LOAD1]])
+  // 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)
   __builtin_dump_struct(&a, &printf);
 }
@@ -312,9 +328,9 @@
   };
 
   // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* [[STRUCT_STR_U13]], i32 0, i32 0))
-  // CHECK: [[RES1:%[−a−zA−Z._0-9]+]] = getelementptr inbounds %struct.U13A, %struct.U13A* %a, i32 0, i32 0
-  // CHECK: [[LOAD1:%[0-9]+]] = load i8*, i8** [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([23 x i8], [23 x i8]* [[FIELD_U13]], i32 0, i32 0), i8* [[LOAD1]])
+  // 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)
   __builtin_dump_struct(&a, &printf);
 }
@@ -329,9 +345,9 @@
   };
 
   // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* [[STRUCT_STR_U14]], i32 0, i32 0))
-  // CHECK: [[RES1:%[−a−zA−Z._0-9]+]] = getelementptr inbounds %struct.U14A, %struct.U14A* %a, i32 0, i32 0
-  // CHECK: [[LOAD1:%[0-9]+]] = load double, double* [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* [[FIELD_U14]], i32 0, i32 0), double [[LOAD1]])
+  // 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)
   __builtin_dump_struct(&a, &printf);
 }
@@ -346,11 +362,27 @@
   };
 
   // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* [[STRUCT_STR_U15]], i32 0, i32 0))
-  // CHECK: [[RES1:%[−a−zA−Z._0-9]+]] = getelementptr inbounds %struct.U15A, %struct.U15A* %a, i32 0, i32 0
-  // CHECK: [[LOAD1:%[0-9]+]] = load [3 x i32], [3 x i32]* [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 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)
-  __builtin_dump_struct(&a, &printf);
+  // CHECK: [[RES1:%.*]] = getelementptr inbounds %struct.U15A, %struct.U15A* %a, 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: [[ARRAY_PTR:%.*]] = getelementptr inbounds [3 x i32], [3 x i32]* [[RES1]], i64 3
+  // CHECK: [[ALLOC_INDEX:%.*]] = alloca i64, i64 1,
+  // CHECK: store i64 0, i64* [[ALLOC_INDEX]],
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[ARRAY_L_SQUARE_U15]], i32 0, i32 0))
+  // CHECK: br label %__builtin_dump_struct.array.body.1
+
+  // CHECK: __builtin_dump_struct.array.body.1:
+  // CHECK: [[INDEX:%.*]] = load i64, i64* [[ALLOC_INDEX]]
+  // CHECK: [[RES2:%.*]] = getelementptr inbounds [3 x i32], [3 x i32]* [[RES1]], i64 0, i64 [[INDEX]]
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([17 x i8], [17 x i8]* [[ARRAY_INDEX_U15]], i32 0, i32 0), i64 [[INDEX]])
+  // CHECK: [[LOAD1:%.*]] = load i32, i32* [[RES2]],
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* [[ARRAY_ELEMENT_U15]], i32 0, i32 0), i32 [[LOAD1]])
+  // CHECK: [[NEXT_INDEX:%.*]] = add i64 [[INDEX]], 1
+  // CHECK: store i64 [[NEXT_INDEX]], i64* [[ALLOC_INDEX]],
+  // CHECK: [[DONE:%.*]] = icmp eq i64 [[NEXT_INDEX]], 3
+  // CHECK: br i1 [[DONE]], label %__builtin_dump_struct.array.done.1, label %__builtin_dump_struct.array.body.1
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* [[ARRAY_R_SQUARE_U15]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[END_STRUCT_U15]], i32 0, i32 0))
+    __builtin_dump_struct(&a, &printf);
 }
 
 void unit16(void) {
@@ -363,9 +395,9 @@
   };
 
   // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* [[STRUCT_STR_U16]], i32 0, i32 0))
-  // CHECK: [[RES1:%[−a−zA−Z._0-9]+]] = getelementptr inbounds %struct.U16A, %struct.U16A* %a, i32 0, i32 0
-  // CHECK: [[LOAD1:%[0-9]+]] = load i8, i8* [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([18 x i8], [18 x i8]* [[FIELD_U16]], i32 0, i32 0), i8 [[LOAD1]])
+  // 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)
   __builtin_dump_struct(&a, &printf);
 }
@@ -380,9 +412,9 @@
   };
 
   // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* [[STRUCT_STR_U17]], i32 0, i32 0))
-  // CHECK: [[RES1:%[−a−zA−Z._0-9]+]] = getelementptr inbounds %struct.U17A, %struct.U17A* %a, i32 0, i32 0
-  // CHECK: [[LOAD1:%[0-9]+]] = load i8, i8* [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([17 x i8], [17 x i8]* [[FIELD_U17]], i32 0, i32 0), i8 [[LOAD1]])
+  // 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)
   __builtin_dump_struct(&a, &printf);
 }
@@ -397,13 +429,64 @@
   };
 
   // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* [[STRUCT_STR_U18]], i32 0, i32 0))
-  // CHECK: [[RES1:%[−a−zA−Z._0-9]+]] = getelementptr inbounds %struct.U18A, %struct.U18A* %a, i32 0, i32 0
-  // CHECK: [[LOAD1:%[0-9]+]] = load x86_fp80, x86_fp80* [[RES1]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([21 x i8], [21 x i8]* [[FIELD_U18]], i32 0, i32 0), x86_fp80 [[LOAD1]])
+  // 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)
   __builtin_dump_struct(&a, &printf);
 }
 
+void unit19(void) {
+  struct T19A {
+    int b[2][2];
+  };
+  struct T19A a = {
+    .b = {{1, 2}, {3, 4}}
+  };
+
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* [[STRUCT_STR_U19]], i32 0, i32 0))
+  // CHECK: [[RES1:%.*]] = getelementptr inbounds %struct.T19A, %struct.T19A* %a, i32 0, i32 0
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([19 x i8], [19 x i8]* [[FIELD_U19]], i32 0, i32 0))
+  // CHECK: [[RES2:%.*]] = getelementptr inbounds [2 x [2 x i32]], [2 x [2 x i32]]* [[RES1]], i64 2
+  // CHECK: [[ALLOC_INDEX:%.*]] = alloca i64, i64 1,
+  // CHECK: store i64 0, i64* [[ALLOC_INDEX]],
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[ARRAY_L_SQUARE_U19]], i32 0, i32 0))
+  // CHECK: br label %__builtin_dump_struct.array.body.1
+
+  // CHECK: __builtin_dump_struct.array.body.1:
+  // CHECK: [[INDEX:%.*]] = load i64, i64* [[ALLOC_INDEX]]
+  // CHECK: [[RES3:%.*]] = getelementptr inbounds [2 x [2 x i32]], [2 x [2 x i32]]* [[RES1]], i64 0, i64 [[INDEX]]
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([17 x i8], [17 x i8]* [[ARRAY_INDEX_U19]], i32 0, i32 0), i64 [[INDEX]])
+  // CHECK: [[RES4:%.*]] = getelementptr inbounds [2 x i32], [2 x i32]* [[RES3]], i64 2
+  // CHECK: [[ALLOC_INDEX1:%.*]] = alloca i64, i64 1,
+  // CHECK: store i64 0, i64* [[ALLOC_INDEX1]],
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[ARRAY_L_SQUARE2_U19]], i32 0, i32 0))
+  // CHECK: br label %__builtin_dump_struct.array.body.2
+
+  // CHECK: __builtin_dump_struct.array.body.2:
+  // CHECK: [[INDEX1:%.*]] = load i64, i64* [[ALLOC_INDEX1]],
+  // CHECK: [[RES5:%.*]] = getelementptr inbounds [2 x i32], [2 x i32]* [[RES3]], i64 0, i64 [[INDEX1]]
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([21 x i8], [21 x i8]* [[ARRAY_INDEX2_U19]], i32 0, i32 0), i64 [[INDEX1]])
+  // CHECK: [[LOAD1:%.*]] = load i32, i32* [[RES5]],
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* [[ARRAY_ELEMENT_U19]], i32 0, i32 0), i32 [[LOAD1]])
+  // CHECK: [[NEXT_INDEX1:%.*]] = add i64 [[INDEX1]], 1
+  // CHECK: store i64 [[NEXT_INDEX1]], i64* [[ALLOC_INDEX1]],
+  // CHECK: [[DONE1:%.*]] = icmp eq i64 [[NEXT_INDEX1]], 2
+  // CHECK: br i1 %20, label %__builtin_dump_struct.array.done.2, label %__builtin_dump_struct.array.body.2
+
+  // CHECK: __builtin_dump_struct.array.done.2:
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* [[ARRAY_R_SQUARE2_U19]], i32 0, i32 0))
+  // CHECK: [[NEXT_INDEX:%.*]] = add i64 [[INDEX]], 1
+  // CHECK: store i64 [[NEXT_INDEX]], i64* [[ALLOC_INDEX]],
+  // CHECK: [[DONE:%.*]] = icmp eq i64 [[NEXT_INDEX]], 2
+  // CHECK: br i1 %25, label %__builtin_dump_struct.array.done.1, label %__builtin_dump_struct.array.body.1
+
+  // CHECK: __builtin_dump_struct.array.done.1:
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* [[ARRAY_R_SQUARE_U19]], i32 0, i32 0))
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([3 x i8], [3 x i8]* [[END_STRUCT_U19]], i32 0, i32 0))
+  __builtin_dump_struct(&a, &printf);
+}
+
 void test1(void) {
   struct T1A {
     int a;
@@ -416,11 +499,11 @@
   };
 
   // CHECK: call i32 (i8*, ...) @printf(
-  // CHECK: [[RES1:%[a-z0-9]+]] = getelementptr inbounds %struct.T1A, %struct.T1A* %a, i32 0, i32 0
-  // CHECK: [[LOAD1:%[0-9]+]] = load i32, i32* [[RES1]],
+  // 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: [[RES2:%[a-z0-9]+]] = getelementptr inbounds %struct.T1A, %struct.T1A* %a, i32 0, i32 1
-  // CHECK: [[LOAD2:%[0-9]+]] = load i8*, i8** [[RES2]],
+  // 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]])
   // CHECK: call i32 (i8*, ...) @printf(
   __builtin_dump_struct(&a, &printf);
@@ -444,13 +527,13 @@
   };
 
   // CHECK: call i32 (i8*, ...) @printf(
-  // CHECK: [[RES1:%[a-z0-9]+]] = getelementptr inbounds %struct.T2B, %struct.T2B* %b, i32 0, i32 0
-  // CHECK: [[LOAD1:%[0-9]+]] = load i32, i32* [[RES1]],
+  // 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: [[NESTED_STRUCT:%[a-z0-9]+]] = getelementptr inbounds %struct.T2B, %struct.T2B* %b, i32 0, i32 1
+  // CHECK: [[NESTED_STRUCT:%.*]] = getelementptr inbounds %struct.T2B, %struct.T2B* %b, i32 0, i32 1
   // CHECK: call i32 (i8*, ...) @printf(
-  // CHECK: [[RES2:%[a-z0-9]+]] = getelementptr inbounds %struct.T2A, %struct.T2A* [[NESTED_STRUCT]], i32 0, i32 0
-  // CHECK: [[LOAD2:%[0-9]+]] = load i32, i32* [[RES2]],
+  // 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(
   __builtin_dump_struct(&b, &printf);
@@ -469,14 +552,30 @@
   };
 
   // CHECK: call i32 (i8*, ...) @printf(
-  // CHECK: [[RES1:%[a-z0-9]+]] = getelementptr inbounds %struct.T3A, %struct.T3A* %a, i32 0, i32 0
+  // CHECK: [[RES1:%.*]] = getelementptr inbounds %struct.T3A, %struct.T3A* %a, i32 0, i32 0
   // CHECK: call i32 (i8*, ...) @printf(
-  // CHECK: [[BC1:%[a-z0-9]+]] = bitcast %union.anon* [[RES1]] to i32*
-  // CHECK: [[LOAD1:%[0-9]+]] = load i32, i32* [[BC1]],
+  // CHECK: [[BC1:%.*]] = bitcast %union.anon* [[RES1]] to i32*
+  // CHECK: [[LOAD1:%.*]] = load i32, i32* [[BC1]],
   // CHECK: call i32 (i8*, ...) @printf({{.*}}, i32 [[LOAD1]])
-  // CHECK: [[BC2:%[a-z0-9]+]] = bitcast %union.anon* [[RES1]] to [4 x i8]*
-  // CHECK: [[LOAD2:%[0-9]+]] = load [4 x i8], [4 x i8]* [[BC2]],
-  // CHECK: call i32 (i8*, ...) @printf({{.*}}, [4 x i8] [[LOAD2]])
+  // CHECK: [[BC2:%.*]] = bitcast %union.anon* [[RES1]] to [4 x i8]*
+  // CHECK: call i32 (i8*, ...) @printf(
+  // CHECK: [[RES2:%.*]] = getelementptr inbounds [4 x i8], [4 x i8]* [[BC2]], i64 4
+  // CHECK: [[ALLOC_INDEX:%.*]] = alloca i64, i64 1,
+  // CHECK: store i64 0, i64* [[ALLOC_INDEX]],
+  // CHECK: call i32 (i8*, ...) @printf(
+  // CHECK: br label %__builtin_dump_struct.array.body.2
+  // CHECK: __builtin_dump_struct.array.body.2:
+  // CHECK: [[INDEX:%.*]] = load i64, i64* [[ALLOC_INDEX]],
+  // CHECK: [[RES3:%.*]] = getelementptr inbounds [4 x i8], [4 x i8]* [[BC2]], i64 0, i64 [[INDEX]]
+  // CHECK: call i32 (i8*, ...) @printf({{.*}}, i64 [[INDEX]])
+  // CHECK: [[LOAD2:%.*]] = load i8, i8* [[RES3]],
+  // CHECK: call i32 (i8*, ...) @printf({{.*}}, i8 [[LOAD2]])
+  // CHECK: [[NEXT_INDEX:%.*]] = add i64 [[INDEX]], 1
+  // CHECK: store i64 [[NEXT_INDEX]], i64* [[ALLOC_INDEX]],
+  // CHECK: [[DONE:%.*]] = icmp eq i64 [[NEXT_INDEX]], 4
+  // CHECK: br i1 %19, label %__builtin_dump_struct.array.done.2, label %__builtin_dump_struct.array.body.2
+  // CHECK: __builtin_dump_struct.array.done.2:
+  // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: call i32 (i8*, ...) @printf(
   __builtin_dump_struct(&a, &printf);
@@ -499,18 +598,18 @@
   };
 
   // CHECK: call i32 (i8*, ...) @printf(
-  // CHECK: [[RES1:%[a-z0-9]+]] = getelementptr inbounds %struct.T4A, %struct.T4A* %a, i32 0, i32 0
+  // CHECK: [[RES1:%.*]] = getelementptr inbounds %struct.T4A, %struct.T4A* %a, i32 0, i32 0
   // CHECK: call i32 (i8*, ...) @printf(
-  // CHECK: [[BC1:%[a-z0-9]+]] = bitcast %union.anon.0* [[RES1]] to %struct.anon*
+  // CHECK: [[BC1:%.*]] = bitcast %union.anon.0* [[RES1]] to %struct.anon*
   // CHECK: call i32 (i8*, ...) @printf(
-  // CHECK: [[RES2:%[a-z0-9]+]] = getelementptr inbounds %struct.anon, %struct.anon* [[BC1]], i32 0, i32 0
-  // CHECK: [[LOAD1:%[0-9]+]] = load i8*, i8** [[RES2]],
+  // 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: [[BC2:%[a-z0-9]+]] = bitcast %union.anon.0* [[RES1]] to %struct.anon.1*
+  // CHECK: [[BC2:%.*]] = bitcast %union.anon.0* [[RES1]] to %struct.anon.1*
   // CHECK: call i32 (i8*, ...) @printf(
-  // CHECK: [[RES3:%[a-z0-9]+]] = getelementptr inbounds %struct.anon.1, %struct.anon.1* [[BC2]], i32 0, i32 0
-  // CHECK: [[LOAD2:%[0-9]+]] = load i64, i64* [[RES3]],
+  // 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]])
   // CHECK: call i32 (i8*, ...) @printf(
   // CHECK: call i32 (i8*, ...) @printf(
@@ -528,11 +627,11 @@
   };
 
   // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([14 x i8], [14 x i8]* {{.*}}, i32 0, i32 0))
-  // CHECK: [[BC1:%[0-9a-z.]+]] = bitcast %struct.T5A* %a to i8*
-  // CHECK: [[LOAD1:%[0-9a-z.]+]] = load i8, i8* [[BC1]],
-  // CHECK: [[CLEAR1:%[0-9a-z.]+]] = and i8 [[LOAD1]], 1
-  // CHECK: [[CAST1:%[0-9a-z.]+]] = zext i8 [[CLEAR1]] to i32
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([25 x i8], [25 x i8]* {{.*}}, i32 0, i32 0), i32 [[CAST1]])
+  // 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(
   __builtin_dump_struct(&a, &printf);
 }
@@ -551,23 +650,23 @@
   };
 
   // CHECK: call i32 (i8*, ...) @printf(
-  // CHECK: [[BC1:%[0-9a-z.]+]] = bitcast %struct.T6A* %a to i8*
-  // CHECK: [[LOAD1:%[0-9a-z.]+]] = load i8, i8* [[BC1]],
-  // CHECK: [[CLEAR1:%[0-9a-z.]+]] = and i8 [[LOAD1]], 1
-  // CHECK: [[CAST1:%[0-9a-z.]+]] = zext i8 [[CLEAR1]] to i32
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([25 x i8], [25 x i8]* {{.*}}, i32 0, i32 0), i32 [[CAST1]])
-  // CHECK: [[BC2:%[0-9a-z.]+]] = bitcast %struct.T6A* %a to i8*
-  // CHECK: [[LOAD2:%[0-9a-z.]+]] = load i8, i8* [[BC2]], align 4
-  // CHECK: [[LSHR2:%[0-9a-z.]+]] = lshr i8 [[LOAD2]], 1
-  // CHECK: [[CLEAR2:%[0-9a-z.]+]] = and i8 [[LSHR2]], 1
-  // CHECK: [[CAST2:%[0-9a-z.]+]] = zext i8 [[CLEAR2]] to i32
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([25 x i8], [25 x i8]* {{.*}}, i32 0, i32 0), i32 [[CAST2]])
-  // CHECK: [[BC3:%[0-9a-z.]+]] = bitcast %struct.T6A* %a to i8*
-  // CHECK: [[LOAD3:%[0-9a-z.]+]] = load i8, i8* [[BC3]], align 4
-  // CHECK: [[LSHR3:%[0-9a-z.]+]] = lshr i8 [[LOAD3]], 2
-  // CHECK: [[CLEAR3:%[0-9a-z.]+]] = and i8 [[LSHR3]], 1
-  // CHECK: [[CAST3:%[0-9a-z.]+]] = zext i8 [[CLEAR3]] to i32
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([25 x i8], [25 x i8]* {{.*}}, i32 0, i32 0), i32 [[CAST3]])
+  // 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: [[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: [[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(
   __builtin_dump_struct(&a, &printf);
 }
@@ -589,19 +688,19 @@
   };
 
   // CHECK: call i32 (i8*, ...) @printf(
-  // CHECK: [[RES1:%[−a−zA−Z._0-9]+]] = getelementptr inbounds %struct.T7B, %struct.T7B* %a, i32 0, i32 0
+  // CHECK: [[RES1:%.*]] = getelementptr inbounds %struct.T7B, %struct.T7B* %a, i32 0, i32 0
   // CHECK: call i32 (i8*, ...) @printf(
-  // CHECK: [[BC1:%[−a−zA−Z._0-9]+]] = bitcast %struct.T7A* [[RES1]] to i8*
-  // CHECK: [[LOAD1:%[-a-zA-Z._0-9]+]] = load i8, i8* [[BC1]],
-  // CHECK: [[CLEAR1:%[-a-zA-Z._0-9]+]] = and i8 [[LOAD1]], 1
-  // CHECK: [[CAST1:%[-a-zA-Z._0-9]+]] = 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: [[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(
-  // CHECK: [[RES2:%[-a-zA-Z._0-9]+]] = getelementptr inbounds %struct.T7B, %struct.T7B* %a, i32 0, i32 1
-  // CHECK: [[LOAD2:%[-a-zA-Z._0-9]+]] = load i8, i8* [[RES2]], align 4
-  // CHECK: [[CLEAR2:%[-a-zA-Z._0-9]+]] = and i8 [[LOAD2]], 1
-  // CHECK: [[CAST2:%[-a-zA-Z._0-9]+]] = zext i8 [[CLEAR2]] to i32
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([25 x i8], [25 x i8]* {{.*}}, i32 0, i32 0), i32 [[CAST2]])
+  // 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(
    __builtin_dump_struct(&a, &printf);
 }
@@ -623,17 +722,17 @@
   // CHECK: [[LOAD1:%[-a-zA-Z._0-9]+]] = load i8, i8* [[BC1]],
   // CHECK: [[CLEAR1:%[-a-zA-Z._0-9]+]] = and i8 [[LOAD1]], 1
   // CHECK: [[CAST1:%[-a-zA-Z._0-9]+]] = zext i8 [[CLEAR1]] to i32
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([25 x i8], [25 x i8]* {{.*}}, i32 0, i32 0), i32 [[CAST1]])
+  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([29 x i8], [29 x i8]* {{.*}}, i32 0, i32 0), i32 [[CAST1]])
   // CHECK: [[BC2:%[−a−zA−Z._0-9]+]] = bitcast %struct.T8A* %a to i8*
   // CHECK: [[LOAD2:%[-a-zA-Z._0-9]+]] = load i8, i8* [[BC2]],
   // CHECK: [[LSHR2:%[0-9a-z.]+]] = lshr i8 [[LOAD2]], 1
   // CHECK: [[CLEAR2:%[-a-zA-Z._0-9]+]] = and i8 [[LSHR2]], 7
   // CHECK: [[CAST2:%[-a-zA-Z._0-9]+]] = zext i8 [[CLEAR2]] to i32
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([23 x i8], [23 x i8]* {{.*}}, i32 0, i32 0), i32 [[CAST2]])
+  // 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(
   // CHECK: [[RES3:%[-a-zA-Z._0-9]+]] = getelementptr inbounds %struct.T8A, %struct.T8A* %a, i32 0, i32 1
   // CHECK: [[LOAD3:%[-a-zA-Z._0-9]+]] = load i32, i32* [[RES3]],
-  // CHECK: call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([21 x i8], [21 x i8]* {{.*}}, i32 0, i32 0), i32 [[LOAD3]])
+  // 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(
   __builtin_dump_struct(&a, &printf);
 }
Index: clang/lib/CodeGen/CGBuiltin.cpp
===================================================================
--- clang/lib/CodeGen/CGBuiltin.cpp
+++ clang/lib/CodeGen/CGBuiltin.cpp
@@ -2043,18 +2043,9 @@
   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();
-  RecordDecl *RD = RType->castAs<RecordType>()->getDecl()->getDefinition();
-  std::string Pad = std::string(Lvl * 4, ' ');
-
-  Value *GString =
-      CGF.Builder.CreateGlobalStringPtr(RType.getAsString() + " {\n");
-  Value *Res = CGF.Builder.CreateCall(Func, {GString});
-
-  static llvm::DenseMap<QualType, const char *> Types;
+static StringRef getDumpStructFormatSpecifier(ASTContext &Context,
+                                              QualType Type) {
+  static llvm::DenseMap<QualType, StringRef> Types;
   if (Types.empty()) {
     Types[Context.CharTy] = "%c";
     Types[Context.BoolTy] = "%d";
@@ -2076,10 +2067,156 @@
     Types[Context.getPointerType(Context.getConstType(Context.CharTy))] = "%s";
   }
 
+  if (Types.find(Type) == Types.end())
+    return Types[Context.VoidPtrTy];
+  return Types[Type];
+}
+
+static llvm::Value *dumpRecord(CodeGenFunction &CGF, QualType RType,
+                               LValue RecordLV, CharUnits Align, bool inArray,
+                               llvm::FunctionCallee Func, int Lvl);
+
+static llvm::Value *dumpArray(CodeGenFunction &CGF, QualType ArrayType,
+                              LValue LV, CharUnits Align,
+                              llvm::FunctionCallee Func, int Lvl) {
+  assert(ArrayType->isConstantArrayType() && "required an array type");
+  auto &Builder = CGF.Builder;
+  ASTContext &Context = CGF.getContext();
+  std::string Pad = std::string(Lvl * 4, ' ');
+  std::string ElementPad = std::string((Lvl + 1) * 4, ' ');
+  std::string &LastElementPad = Pad;
+  std::string Name = "__builtin_dump_struct.array.";
+
+  auto GetConstInt = [&CGF](int64_t Val) -> llvm::ConstantInt * {
+    return llvm::ConstantInt::get(CGF.IntPtrTy, Val, true);
+  };
+
+  auto GetInstName = [&Name, &Lvl](StringRef Suffix) -> std::string {
+    return llvm::Twine(Name)
+        .concat(Suffix)
+        .concat(".")
+        .concat(llvm::Twine(Lvl))
+        .str();
+  };
+
+  const ConstantArrayType *CAT = Context.getAsConstantArrayType(ArrayType);
+  QualType ElementType = CAT->getElementType();
+  Address ArrayAddress = LV.getAddress(CGF);
+
+  CharUnits ElementAlign = ArrayAddress.getAlignment().alignmentOfArrayElement(
+      Context.getTypeSizeInChars(ArrayType));
+
+  const llvm::ArrayType *LLVMArrayType =
+      dyn_cast<llvm::ArrayType>(ArrayAddress.getElementType());
+
+  // The length of an array in elements, as well as the base element type and a
+  // properly-typed first element pointer.
+  llvm::Value *Length = GetConstInt(LLVMArrayType->getNumElements());
+
+  // Normally we have to check whether the array is zero-length.
+  bool CheckZeroLength = true;
+  // But if the array length is constant, we can suppress that.
+  if (llvm::ConstantInt *CL = dyn_cast<llvm::ConstantInt>(Length)) {
+    // ...and if it's constant zero, we can just skip the entire thing.
+    if (!CL->isZero())
+      CheckZeroLength = false;
+  }
+
+  llvm::Value *Begin = ArrayAddress.getPointer();
+  llvm::Value *End =
+      Builder.CreateInBoundsGEP(ArrayAddress.getElementType(), Begin, Length);
+
+  Address IndexAddr = CGF.CreateTempAlloca(CGF.IntPtrTy, CGF.getSizeAlign(),
+                                           "index", GetConstInt(1), nullptr);
+  llvm::Value *Index = Builder.CreateStore(GetConstInt(0), IndexAddr);
+
+  // The basic structure here is a do-while loop, because we don't
+  // need to check for the zero-element case.
+  llvm::BasicBlock *BodyBB = CGF.createBasicBlock(GetInstName("body"));
+  llvm::BasicBlock *DoneBB = CGF.createBasicBlock(GetInstName("done"));
+
+  if (CheckZeroLength) {
+    llvm::Value *isEmpty =
+        Builder.CreateICmpEQ(Begin, End, GetInstName("isempty"));
+    CGF.Builder.CreateCondBr(isEmpty, DoneBB, BodyBB);
+  }
+
+  llvm::Value *GString = Builder.CreateGlobalStringPtr("[\n");
+  llvm::Value *Res = Builder.CreateCall(Func, {GString});
+  llvm::Value *TmpRes = nullptr;
+
+  CGF.EmitBlock(BodyBB);
+  Index = Builder.CreateLoad(IndexAddr);
+  llvm::Value *Element = Builder.CreateInBoundsGEP(
+      ArrayAddress.getElementType(), ArrayAddress.getPointer(),
+      {CGF.CGM.getSize(CharUnits::Zero()), Index});
+  Address ElementAddr =
+      Address(Element, LLVMArrayType->getElementType(), ElementAlign);
+  LValue ElementLV = CGF.MakeAddrLValue(ElementAddr, ElementType);
+
+  GString = Builder.CreateGlobalStringPtr(
+      llvm::Twine(ElementPad).concat("[%ld] = ").str());
+  TmpRes = CGF.Builder.CreateCall(Func, {GString, Index});
+  Res = CGF.Builder.CreateAdd(Res, TmpRes);
+
+  if (ElementType->isConstantArrayType()) {
+    TmpRes =
+        dumpArray(CGF, ElementType, ElementLV, ElementAlign, Func, Lvl + 1);
+    Res = Builder.CreateAdd(Res, TmpRes);
+  } else {
+    if (ElementType->isRecordType()) {
+      TmpRes = dumpRecord(CGF, ElementType, ElementLV, ElementAlign, true, Func,
+                          Lvl + 1);
+    } else {
+      StringRef Format = getDumpStructFormatSpecifier(Context, ElementType);
+      GString =
+          Builder.CreateGlobalStringPtr(llvm::Twine(Format).concat("\n").str());
+      RValue RV = CGF.EmitLoadOfLValue(ElementLV, SourceLocation());
+      TmpRes = CGF.Builder.CreateCall(Func, {GString, RV.getScalarVal()});
+    }
+    Res = CGF.Builder.CreateAdd(Res, TmpRes);
+  }
+
+  Index = Builder.CreateAdd(Index, GetConstInt(1));
+  Builder.CreateStore(Index, IndexAddr);
+
+  llvm::Value *Done = Builder.CreateICmpEQ(Index, Length);
+  Builder.CreateCondBr(Done, DoneBB, BodyBB);
+
+  CGF.EmitBlock(DoneBB);
+  GString = Builder.CreateGlobalStringPtr(
+      llvm::Twine(LastElementPad).concat("]\n").str());
+  TmpRes = Builder.CreateCall(Func, {GString});
+  Res = Builder.CreateAdd(TmpRes, Res);
+  return Res;
+}
+
+static llvm::Value *dumpRecord(CodeGenFunction &CGF, QualType RType,
+                               LValue RecordLV, CharUnits Align, bool inArray,
+                               llvm::FunctionCallee Func, int Lvl) {
+  ASTContext &Context = CGF.getContext();
+  RecordDecl *RD = RType->castAs<RecordType>()->getDecl()->getDefinition();
+  std::string Pad = std::string(Lvl * 4, ' ');
+  std::string FieldPad = std::string((Lvl + 1) * 4, ' ');
+
+  Value *GString = nullptr;
+  if (!inArray) {
+    PrintingPolicy Policy(Context.getLangOpts());
+    Policy.AnonymousTagLocations = false;
+    GString =
+        CGF.Builder.CreateGlobalStringPtr(llvm::Twine(Pad)
+                                              .concat(RType.getAsString(Policy))
+                                              .concat(" {\n")
+                                              .str());
+  } else {
+    GString = CGF.Builder.CreateGlobalStringPtr("{\n");
+  }
+  Value *Res = CGF.Builder.CreateCall(Func, {GString});
+
   for (const auto *FD : RD->fields()) {
     Value *TmpRes = nullptr;
 
-    std::string Format = llvm::Twine(Pad)
+    std::string Format = llvm::Twine(FieldPad)
                              .concat(FD->getType().getAsString())
                              .concat(llvm::Twine(' '))
                              .concat(FD->getNameAsString())
@@ -2111,15 +2248,24 @@
 
     // We check whether we are in a recursive type
     if (CanonicalType->isRecordType()) {
-      TmpRes = dumpRecord(CGF, CanonicalType, FieldLV, Align, Func, Lvl + 1);
+      TmpRes =
+          dumpRecord(CGF, CanonicalType, FieldLV, Align, false, Func, Lvl + 1);
+      Res = CGF.Builder.CreateAdd(TmpRes, Res);
+      continue;
+    }
+
+    if (CanonicalType->isConstantArrayType()) {
+      GString = CGF.Builder.CreateGlobalStringPtr(
+          llvm::Twine(Format).concat(" = ").str());
+      TmpRes = CGF.Builder.CreateCall(Func, {GString});
+      Res = CGF.Builder.CreateAdd(Res, TmpRes);
+      TmpRes = dumpArray(CGF, CanonicalType, FieldLV, Align, Func, 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];
+    StringRef TypeFormat = getDumpStructFormatSpecifier(Context, CanonicalType);
 
     GString = CGF.Builder.CreateGlobalStringPtr(llvm::Twine(Format)
                                                     .concat(" = ")
@@ -2678,7 +2824,7 @@
 
     Value *RecordPtr = EmitScalarExpr(Arg0);
     LValue RecordLV = MakeAddrLValue(RecordPtr, Arg0Type, Arg0Align);
-    Value *Res = dumpRecord(*this, Arg0Type, RecordLV, Arg0Align,
+    Value *Res = dumpRecord(*this, Arg0Type, RecordLV, Arg0Align, false,
                             {LLVMFuncType, Func}, 0);
     return RValue::get(Res);
   }
Index: clang/docs/ReleaseNotes.rst
===================================================================
--- clang/docs/ReleaseNotes.rst
+++ clang/docs/ReleaseNotes.rst
@@ -90,6 +90,9 @@
   `51414 <https://github.com/llvm/llvm-project/issues/51414>`_,
   `51416 <https://github.com/llvm/llvm-project/issues/51416>`_,
   and `51641 <https://github.com/llvm/llvm-project/issues/51641>`_.
+- The builtin function __builtin_dump_struct would crash clang when the target 
+  struct have bitfield. Now it fixed.
+  This fixes Issue `Issue 54462 <https://github.com/llvm/llvm-project/issues/54462>`_.
 
 
 Improvements to Clang's diagnostics
@@ -107,10 +110,9 @@
 
 Non-comprehensive list of changes in this release
 -------------------------------------------------
-- The builtin function __builtin_dump_struct would crash clang when the target 
-  struct have bitfield. Now it fixed, and __builtin_dump_struct support dump
-  the bitwidth of bitfields.
-  This fixes `Issue 54462 <https://github.com/llvm/llvm-project/issues/54462>`_.
+- The builtin function __builtin_dump_struct support dump constant array and the 
+  bitwidth of bitfields in a struct.
+  
 
 New Compiler Flags
 ------------------
@@ -152,12 +154,6 @@
 - The ``__declspec(naked)`` attribute can no longer be written on a member
   function in Microsoft compatibility mode, matching the behavior of cl.exe.
 
-- Improve __builtin_dump_struct:
-
-  - Support bitfields in struct and union.
-  
-  - Improve the dump format, dump both bitwidth(if its a bitfield) and field value.
-
 Windows Support
 ---------------
 
Index: clang/docs/LanguageExtensions.rst
===================================================================
--- clang/docs/LanguageExtensions.rst
+++ clang/docs/LanguageExtensions.rst
@@ -2375,12 +2375,22 @@
 .. code-block:: c++
 
      struct S {
-       int x, y;
-       float f;
-       struct T {
-         int i;
-       } t;
-     };
+      int x;
+      int y : 1;
+      int : 0;
+      int b[2][2];
+      float f;
+      struct T {
+        int i;
+      } t;
+      struct {
+        int i;
+      } foo;
+      struct Bar {
+          int x;
+          const char *B;
+        } bar[2];
+    };
 
      void func(struct S *s) {
        __builtin_dump_struct(s, &printf);
@@ -2391,13 +2401,37 @@
 .. code-block:: none
 
      struct S {
-     int i : 100
-     int j : 42
-     float f : 3.14159
-     struct T t : struct T {
-         int i : 1997
-         }
-     }
+        int x = 100
+        int y : 1 = 0
+        int : 0
+        int[2][2] b = [
+            [0] = [
+                [0] = 1
+                [1] = 2
+            ]
+            [1] = [
+                [0] = 3
+                [1] = 4
+            ]
+        ]
+        float f = 0.000000
+        struct T {
+            int i = 2022
+        }
+        struct S::(unnamed) {
+            int i = 4096
+        }
+        struct Bar[2] bar = [
+            [0] = {
+                int x = 1024
+                const char * B = This is struct Bar[0]
+            }
+            [1] = {
+                int x = 2048
+                const char * B = This is struct Bar[1]
+            }
+        ]
+    }
 
 **Description**:
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to