// 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; }