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