|  | // Check that backend stack layout diagnostics are working correctly with and | 
|  | // without debug information, and when optimizations are enabled | 
|  | // | 
|  | // REQUIRES: x86-registered-target | 
|  | // | 
|  | // RUN: rm -rf %t | 
|  | // RUN: mkdir -p %t | 
|  | // RUN: %clang_cc1 %s -emit-codegen-only -triple x86_64-unknown-linux-gnu -target-cpu corei7 -Rpass-analysis=stack-frame-layout -o /dev/null  -O0  2>&1 | FileCheck %s --check-prefix=O0-NODEBUG | 
|  | // RUN: %clang_cc1 %s -emit-codegen-only -triple x86_64-unknown-linux-gnu -target-cpu corei7 -Rpass-analysis=stack-frame-layout -o /dev/null  -O0  -debug-info-kind=constructor  -dwarf-version=5 -debugger-tuning=gdb 2>&1 | FileCheck %s --check-prefix=O0-DEBUG | 
|  | // RUN: %clang_cc1 %s -emit-codegen-only -triple x86_64-unknown-linux-gnu -target-cpu corei7 -funwind-tables=2 -O3 -Rpass-analysis=stack-frame-layout   -debug-info-kind=constructor  -dwarf-version=5 -debugger-tuning=gdb -opt-record-file %t/stack-layout-remark.c.yml -opt-record-passes stack-frame-layout 2>&1 | FileCheck %s --check-prefix=O3-DEBUG | 
|  | // RUN: cat %t/stack-layout-remark.c.yml | FileCheck %s --check-prefix=YAML | 
|  |  | 
|  | #define NULL (void*)0 | 
|  |  | 
|  | extern void* allocate(unsigned size); | 
|  | extern void deallocate(void* ptr); | 
|  | extern int work(char *ary, int size); | 
|  | extern int rand(void); | 
|  |  | 
|  | // Test YAML Ouput | 
|  | // YAML: --- !Analysis | 
|  | // YAML: Pass:            stack-frame-layout | 
|  | // YAML: Name:            StackLayout | 
|  | // YAML: DebugLoc:        { File: '{{.*}}stack-layout-remark.c',{{[[:space:]]*}}Line: [[# @LINE + 24]], | 
|  | // YAML: Function:        foo | 
|  | // YAML: Args: | 
|  | // YAML:   - Offset:          '-40' | 
|  | // YAML:   - Type:            Variable | 
|  | // YAML:   - Align:           '16' | 
|  | // YAML:   - Size:            '32' | 
|  | // YAML:   - DataLoc:         'a @ {{.*}}stack-layout-remark.c:[[# @LINE + 19]]' | 
|  | // YAML:   - DataLoc:         'f @ {{.*}}stack-layout-remark.c:[[# @LINE + 21]]' | 
|  |  | 
|  | //      O0-NODEBUG: Function: foo | 
|  | // O0-NODEBUG-NEXT: Offset: [SP-40], Type: Variable, Align: 16, Size: 32 | 
|  | // O0-NODEBUG-NEXT: Offset: [SP-72], Type: Variable, Align: 16, Size: 32 | 
|  | // | 
|  | //      O0-DEBUG: Function: foo | 
|  | // O0-DEBUG-NEXT: Offset: [SP-40], Type: Variable, Align: 16, Size: 32 | 
|  | // O0-DEBUG-NEXT:     a @ {{.*}}stack-layout-remark.c:[[# @LINE + 10]] | 
|  | // O0-DEBUG-NEXT: Offset: [SP-72], Type: Variable, Align: 16, Size: 32 | 
|  | // O0-DEBUG-NEXT:     f @ {{.*}}stack-layout-remark.c:[[# @LINE + 11]] | 
|  |  | 
|  | //      O3-DEBUG: Function: foo | 
|  | // O3-DEBUG-NEXT: Offset: [SP-40], Type: Variable, Align: 16, Size: 32 | 
|  | // O3-DEBUG-NEXT:     a @ {{.*}}stack-layout-remark.c:[[# @LINE + 4]] | 
|  | // O3-DEBUG-NEXT:     f @ {{.*}}stack-layout-remark.c:[[# @LINE + 6]] | 
|  | void foo() { | 
|  | { | 
|  | char a[32] = {0}; | 
|  | work(a, sizeof(a)); | 
|  | } | 
|  | char f[32] = {0}; | 
|  | work(f, sizeof(f)); | 
|  | } | 
|  | //      O0-NODEBUG: Function: bar | 
|  | // O0-NODEBUG-NEXT: Offset: [SP-40], Type: Variable, Align: 16, Size: 32 | 
|  | // O0-NODEBUG-NEXT: Offset: [SP-72], Type: Variable, Align: 16, Size: 32 | 
|  |  | 
|  | //      O0-DEBUG: Function: bar | 
|  | // O0-DEBUG-NEXT: Offset: [SP-40], Type: Variable, Align: 16, Size: 32 | 
|  | // O0-DEBUG-NEXT:     f @ {{.*}}stack-layout-remark.c:[[# @LINE + 10]] | 
|  | // O0-DEBUG-NEXT: Offset: [SP-72], Type: Variable, Align: 16, Size: 32 | 
|  | // O0-DEBUG-NEXT:     a @ {{.*}}stack-layout-remark.c:[[# @LINE + 10]] | 
|  |  | 
|  | //      O3-DEBUG: Function: bar | 
|  | // O3-DEBUG-NEXT: Offset: [SP-40], Type: Variable, Align: 16, Size: 32 | 
|  | // O3-DEBUG-NEXT:     f @ {{.*}}stack-layout-remark.c:[[# @LINE + 4]] | 
|  | // O3-DEBUG-NEXT: Offset: [SP-72], Type: Variable, Align: 16, Size: 32 | 
|  | // O3-DEBUG-NEXT:     a @ {{.*}}stack-layout-remark.c:[[# @LINE + 4]] | 
|  | void bar() { | 
|  | char f[32] = {0}; | 
|  | { | 
|  | char a[32] = {0}; | 
|  | work(a, sizeof(a)); | 
|  | } | 
|  | work(f, sizeof(f)); | 
|  | } | 
|  |  | 
|  | struct Array { | 
|  | int *data; | 
|  | int size; | 
|  | }; | 
|  |  | 
|  | struct Result { | 
|  | struct Array *data; | 
|  | int sum; | 
|  | }; | 
|  |  | 
|  | //      O0-NODEBUG: Function: cleanup_array | 
|  | // O0-NODEBUG-NEXT: Offset: [SP-8], Type: Variable, Align: 8, Size: 8 | 
|  |  | 
|  | //      O0-DEBUG: Function: cleanup_array | 
|  | // O0-DEBUG-NEXT: Offset: [SP-8], Type: Variable, Align: 8, Size: 8 | 
|  | // O0-DEBUG-NEXT:     a @ {{.*}}stack-layout-remark.c:[[# @LINE + 5]] | 
|  |  | 
|  | //      O3-DEBUG: Function: cleanup_array | 
|  | //      O3-DEBUG: Function: cleanup_result | 
|  | // O3-DEBUG-NEXT: Offset: [SP-8], Type: Spill, Align: 16, Size: 8 | 
|  | void cleanup_array(struct Array *a) { | 
|  | if (!a) | 
|  | return; | 
|  | if (!a->data) | 
|  | return; | 
|  | deallocate(a->data); | 
|  | } | 
|  |  | 
|  | //      O0-NODEBUG: Function: cleanup_result | 
|  | // O0-NODEBUG-NEXT: Offset: [SP-8], Type: Variable, Align: 8, Size: 8 | 
|  |  | 
|  | //      O0-DEBUG: Function: cleanup_result | 
|  | // O0-DEBUG-NEXT: Offset: [SP-8], Type: Variable, Align: 8, Size: 8 | 
|  | // O0-DEBUG-NEXT:     res @ {{.*}}stack-layout-remark.c:[[# @LINE + 1]] | 
|  | void cleanup_result(struct Result *res) { | 
|  | if (!res) | 
|  | return; | 
|  | if (!res->data) | 
|  | return; | 
|  | cleanup_array(res->data); | 
|  | deallocate(res->data); | 
|  | } | 
|  |  | 
|  | extern void use_dot_vector(struct Array *data); | 
|  |  | 
|  | //      O0-NODEBUG: Function: do_work | 
|  | // O0-NODEBUG-NEXT: Offset: [SP-4], Type: Variable, Align: 4, Size: 4 | 
|  | // O0-NODEBUG-NEXT: Offset: [SP-16], Type: Variable, Align: 8, Size: 8 | 
|  | // O0-NODEBUG-NEXT: Offset: [SP-24], Type: Variable, Align: 8, Size: 8 | 
|  | // O0-NODEBUG-NEXT: Offset: [SP-32], Type: Variable, Align: 8, Size: 8 | 
|  | // O0-NODEBUG-NEXT: Offset: [SP-36], Type: Variable, Align: 4, Size: 4 | 
|  | // O0-NODEBUG-NEXT: Offset: [SP-48], Type: Variable, Align: 8, Size: 8 | 
|  | // O0-NODEBUG-NEXT: Offset: [SP-52], Type: Variable, Align: 4, Size: 4 | 
|  | // O0-NODEBUG-NEXT: Offset: [SP-56], Type: Variable, Align: 4, Size: 4 | 
|  |  | 
|  | //      O0-DEBUG: Function: do_work | 
|  | // O0-DEBUG-NEXT: Offset: [SP-4], Type: Variable, Align: 4, Size: 4 | 
|  | // O0-DEBUG-NEXT: Offset: [SP-16], Type: Variable, Align: 8, Size: 8 | 
|  | // O0-DEBUG-NEXT:     A @ {{.*}}stack-layout-remark.c:[[# @LINE + 20]] | 
|  | // O0-DEBUG-NEXT: Offset: [SP-24], Type: Variable, Align: 8, Size: 8 | 
|  | // O0-DEBUG-NEXT:     B @ {{.*}}stack-layout-remark.c:[[# @LINE + 18]] | 
|  | // O0-DEBUG-NEXT: Offset: [SP-32], Type: Variable, Align: 8, Size: 8 | 
|  | // O0-DEBUG-NEXT:     out @ {{.*}}stack-layout-remark.c:[[# @LINE + 16]] | 
|  | // O0-DEBUG-NEXT: Offset: [SP-36], Type: Variable, Align: 4, Size: 4 | 
|  | // O0-DEBUG-NEXT:     len @ {{.*}}stack-layout-remark.c:[[# @LINE + 19]] | 
|  | // O0-DEBUG-NEXT: Offset: [SP-48], Type: Variable, Align: 8, Size: 8 | 
|  | // O0-DEBUG-NEXT:     AB @ {{.*}}stack-layout-remark.c:[[# @LINE + 18]] | 
|  | // O0-DEBUG-NEXT: Offset: [SP-52], Type: Variable, Align: 4, Size: 4 | 
|  | // O0-DEBUG-NEXT:     sum @ {{.*}}stack-layout-remark.c:[[# @LINE + 32]] | 
|  | // O0-DEBUG-NEXT: Offset: [SP-56], Type: Variable, Align: 4, Size: 4 | 
|  | // O0-DEBUG-NEXT:     i @ {{.*}}stack-layout-remark.c:[[# @LINE + 31]] | 
|  |  | 
|  | //      O3-DEBUG: Function: do_work | 
|  | // O3-DEBUG-NEXT: Offset: [SP-8], Type: Spill, Align: 16, Size: 8 | 
|  | // O3-DEBUG-NEXT: Offset: [SP-16], Type: Spill, Align: 8, Size: 8 | 
|  | // O3-DEBUG-NEXT: Offset: [SP-24], Type: Spill, Align: 16, Size: 8 | 
|  | // O3-DEBUG-NEXT: Offset: [SP-32], Type: Spill, Align: 8, Size: 8 | 
|  | // O3-DEBUG-NEXT: Offset: [SP-40], Type: Spill, Align: 16, Size: 8 | 
|  | int do_work(struct Array *A, struct Array *B, struct Result *out) { | 
|  | if (!A || !B) | 
|  | return -1; | 
|  | if (A->size != B->size) | 
|  | return -1; | 
|  | const int len = A->size; | 
|  | struct Array *AB; | 
|  | if (out->data == NULL) { | 
|  | AB = (struct Array *)allocate(sizeof(struct Array)); | 
|  | AB->data = NULL; | 
|  | AB->size = 0; | 
|  | out->data = AB; | 
|  | } else { | 
|  | AB = out->data; | 
|  | } | 
|  |  | 
|  | if (AB->data) | 
|  | deallocate(AB->data); | 
|  |  | 
|  | AB->data = (int *)allocate(len * sizeof(int)); | 
|  | AB->size = len; | 
|  |  | 
|  | int sum = 0; | 
|  | for (int i = 0; i < len; ++i) { | 
|  | AB->data[i] = A->data[i] * B->data[i]; | 
|  | sum += AB->data[i]; | 
|  | } | 
|  | return sum; | 
|  | } | 
|  |  | 
|  | //      O0-NODEBUG: Function: gen_array | 
|  | // O0-NODEBUG-NEXT: Offset: [SP-8], Type: Variable, Align: 8, Size: 8 | 
|  | // O0-NODEBUG-NEXT: Offset: [SP-12], Type: Variable, Align: 4, Size: 4 | 
|  | // O0-NODEBUG-NEXT: Offset: [SP-24], Type: Variable, Align: 8, Size: 8 | 
|  | // O0-NODEBUG-NEXT: Offset: [SP-28], Type: Variable, Align: 4, Size: 4 | 
|  |  | 
|  | //      O0-DEBUG: Function: gen_array | 
|  | // O0-DEBUG-NEXT: Offset: [SP-8], Type: Variable, Align: 8, Size: 8 | 
|  | // O0-DEBUG-NEXT: Offset: [SP-12], Type: Variable, Align: 4, Size: 4 | 
|  | // O0-DEBUG-NEXT:     size @ {{.*}}stack-layout-remark.c:[[# @LINE + 10]] | 
|  | // O0-DEBUG-NEXT: Offset: [SP-24], Type: Variable, Align: 8, Size: 8 | 
|  | // O0-DEBUG-NEXT:     res @ {{.*}}stack-layout-remark.c:[[# @LINE + 11]] | 
|  | // O0-DEBUG-NEXT: Offset: [SP-28], Type: Variable, Align: 4, Size: 4 | 
|  | // O0-DEBUG-NEXT:     i @ {{.*}}stack-layout-remark.c:[[# @LINE + 13]] | 
|  |  | 
|  | //      O3-DEBUG: Function: gen_array | 
|  | // O3-DEBUG-NEXT: Offset: [SP-8], Type: Spill, Align: 16, Size: 8 | 
|  | // O3-DEBUG-NEXT: Offset: [SP-16], Type: Spill, Align: 8, Size: 8 | 
|  | // O3-DEBUG-NEXT: Offset: [SP-24], Type: Spill, Align: 16, Size: 8 | 
|  | struct Array *gen_array(int size) { | 
|  | if (size < 0) | 
|  | return NULL; | 
|  | struct Array *res = (struct Array *)allocate(sizeof(struct Array)); | 
|  | res->size = size; | 
|  | res->data = (int *)allocate(size * sizeof(int)); | 
|  |  | 
|  | for (int i = 0; i < size; ++i) { | 
|  | res->data[i] = rand(); | 
|  | } | 
|  |  | 
|  | return res; | 
|  | } | 
|  |  | 
|  | // YAML: --- !Analysis | 
|  | // YAML: Pass:            stack-frame-layout | 
|  | // YAML: Name:            StackLayout | 
|  | // YAML: DebugLoc:        { File: '{{.*}}stack-layout-remark.c',{{[[:space:]]*}}Line: [[# @LINE + 59]], | 
|  | // YAML: Function:        caller | 
|  | // YAML: Args: | 
|  | // YAML:   - Offset:          '-8' | 
|  | // YAML:   - Type:            Spill | 
|  | // YAML:   - Align:           '16' | 
|  | // YAML:   - Size:            '8' | 
|  | // YAML:   - Offset:          '-16' | 
|  | // YAML:   - Type:            Spill | 
|  | // YAML:   - Align:           '8' | 
|  | // YAML:   - Size:            '8' | 
|  | // YAML:   - Offset:          '-24' | 
|  | // YAML:   - Type:            Spill | 
|  | // YAML:   - Align:           '16' | 
|  | // YAML:   - Size:            '8' | 
|  | // YAML:   - Offset:          '-32' | 
|  | // YAML:   - Type:            Spill | 
|  | // YAML:   - Align:           '8' | 
|  | // YAML:   - Size:            '8' | 
|  | // YAML:   - Offset:          '-40' | 
|  | // YAML:   - Type:            Spill | 
|  | // YAML:   - Align:           '16' | 
|  | // YAML:   - Size:            '8' | 
|  | // YAML:   - Offset:          '-48' | 
|  | // YAML:   - Type:            Spill | 
|  | // YAML:   - Align:           '8' | 
|  | // YAML:   - Size:            '8' | 
|  |  | 
|  | //      O0-NODEBUG: Function: caller | 
|  | // O0-NODEBUG-NEXT: Offset: [SP-4], Type: Variable, Align: 4, Size: 4 | 
|  | // O0-NODEBUG-NEXT: Offset: [SP-8], Type: Variable, Align: 4, Size: 4 | 
|  | // O0-NODEBUG-NEXT: Offset: [SP-16], Type: Variable, Align: 8, Size: 8 | 
|  | // O0-NODEBUG-NEXT: Offset: [SP-24], Type: Variable, Align: 8, Size: 8 | 
|  | // O0-NODEBUG-NEXT: Offset: [SP-32], Type: Variable, Align: 8, Size: 8 | 
|  | // O0-NODEBUG-NEXT: Offset: [SP-36], Type: Variable, Align: 4, Size: 4 | 
|  | // O0-NODEBUG-NEXT: Offset: [SP-40], Type: Variable, Align: 4, Size: 4 | 
|  |  | 
|  | //      O0-DEBUG: Function: caller | 
|  | // O0-DEBUG-NEXT: Offset: [SP-4], Type: Variable, Align: 4, Size: 4 | 
|  | // O0-DEBUG-NEXT: Offset: [SP-8], Type: Variable, Align: 4, Size: 4 | 
|  | // O0-DEBUG-NEXT:     size @ {{.*}}stack-layout-remark.c:[[# @LINE + 20]] | 
|  | // O0-DEBUG-NEXT: Offset: [SP-16], Type: Variable, Align: 8, Size: 8 | 
|  | // O0-DEBUG-NEXT:     A @ {{.*}}stack-layout-remark.c:[[# @LINE + 19]] | 
|  | // O0-DEBUG-NEXT: Offset: [SP-24], Type: Variable, Align: 8, Size: 8 | 
|  | // O0-DEBUG-NEXT:     B @ {{.*}}stack-layout-remark.c:[[# @LINE + 18]] | 
|  | // O0-DEBUG-NEXT: Offset: [SP-32], Type: Variable, Align: 8, Size: 8 | 
|  | // O0-DEBUG-NEXT:     res @ {{.*}}stack-layout-remark.c:[[# @LINE + 17]] | 
|  | // O0-DEBUG-NEXT: Offset: [SP-36], Type: Variable, Align: 4, Size: 4 | 
|  | // O0-DEBUG-NEXT:     ret @ {{.*}}stack-layout-remark.c:[[# @LINE + 16]] | 
|  | // O0-DEBUG-NEXT: Offset: [SP-40], Type: Variable, Align: 4, Size: 4 | 
|  | // O0-DEBUG-NEXT:     err @ {{.*}}stack-layout-remark.c:[[# @LINE + 16]] | 
|  |  | 
|  | //      O3-DEBUG: Function: caller | 
|  | // O3-DEBUG-NEXT: Offset: [SP-8], Type: Spill, Align: 16, Size: 8 | 
|  | // O3-DEBUG-NEXT: Offset: [SP-16], Type: Spill, Align: 8, Size: 8 | 
|  | // O3-DEBUG-NEXT: Offset: [SP-24], Type: Spill, Align: 16, Size: 8 | 
|  | // O3-DEBUG-NEXT: Offset: [SP-32], Type: Spill, Align: 8, Size: 8 | 
|  | // O3-DEBUG-NEXT: Offset: [SP-40], Type: Spill, Align: 16, Size: 8 | 
|  | // O3-DEBUG-NEXT: Offset: [SP-48], Type: Spill, Align: 8, Size: 8 | 
|  | int caller() { | 
|  | const int size = 100; | 
|  | struct Array *A = gen_array(size); | 
|  | struct Array *B = gen_array(size); | 
|  | struct Result *res = (struct Result *)allocate(sizeof(struct Result)); | 
|  | int ret = -1; | 
|  |  | 
|  | int err = do_work(A, B, res); | 
|  | if (err == -1) { | 
|  | goto cleanup; | 
|  | } | 
|  |  | 
|  | ret = res->sum; | 
|  | if (ret == -1) | 
|  | return caller(); | 
|  |  | 
|  | use_dot_vector(res->data); | 
|  |  | 
|  | cleanup: | 
|  | cleanup_array(A); | 
|  | cleanup_array(B); | 
|  | cleanup_result(res); | 
|  |  | 
|  | return ret; | 
|  | } | 
|  |  |